Review my weekend project: Webapp to add CSS to any website and share the result - <AUTHOR> http://www.csspivot.com

<comment><USER2> One of my favourite HN projects in a long time.

You'll have to do a blog post on how you pulled it off some time.

Design feedback is going to be so friggin' easy from now on. If you ever begin to lose money on this, I'd love to buy a premium account or look into a subscription model.

(Regardless, you should look into a premium user program. Some ideas: prioritized bandwidth, custom shorturl for credit(?) such as /<user>/<shorturl>, a profile to save a history and metrics similar to URL- shortening services. No ads.

It'd seriously be stupid not to monetize this; I can't emphasize how much I love your concept.)

You could also reach out to companies looking for redesigns (or -aligns) and find a way to match them with a designer.

Remember to put up a link on Forrst. Heck, you could turn this into a design community by your own, where people share redesigns of sites - and you could implement a favourite and upvote system to reward the best ones. Showing users how shitty airline websites could look - not just as Adobe mock-ups - is very powerful. Set up some basic Django, include some thumbnails of each site link and implement a basic upvote and favourite system - boom, Dribbble for CSS. Scale later. Basically imitate all the monetization Kyle has done for Forrst.

As someone gravitating between college and no job, finding a way to prove my skills publicly is very difficult. This service would be great to leverage and would make it very easy to accomplish this feat. A premium user system could also allow people to include a pretty embed csspivot portfolio.

And then there's the whole let-me-show-you-what-I-can-do-for-you-application discussion[1].

If I were anyone on HN, I'd pitch him an offer for a banner on the site, because there's a very good chance that this blows up and goes viral. If I had a site or service to plug, I'd already have done this. Here is his Twitter profile, the only contact information I can see: <http://twitter.com/metachris>.

[1]: <http://news.ycombinator.com/item?id=2361034>

<comment><AUTHOR> Wow thanks for the great response! A lot to think about -- I'd definitely love to do something more with it! My contact is chris (at) metachris.org if anybody wants to get in touch.

[edit] kmfrk: just wanted to send you a mail, but you haven't got a contact in your profile

<comment><USER2> Sending you an e-mail. It's n...email@example.com.

</comment></comment></comment><comment><USER3> This is cool. A few suggestions:

* Add a way to delete previews you've made.

* Add more viral hooks. FB wall post, email, etc.

* Do the same concept but with javascript.

* Load each website in a frame with a 50px bar at the top or bottom with your branding and more options. This is where you'll monetize. I know you're focused on usability right now, but if it goes viral you need it to pay you or it will go away.

* Don't bother with premium features until you have a working viral loop providing consistent growth.

Best of luck!!

<comment><USER4> I imagine that doing the same concept with javascript would make you an attractive hosting service for phishers.

<comment><USER5> Not if you add some banner at the top.

</comment></comment></comment><comment><USER6> Very awesome! Suggestions:

1\. Revamp the "Recently viewed" and "new" lists to show the domains instead of the slugs.

2\. Add "Most popular CSS pivots" for global and for a specific domain, track the most popular domains for pivots. Possibly add upvote/downvote ratings ala HN/Reddit.

3\. Promote competitions for "CSS pivoting" specific sites. For example, "Best rated news.ycombinator.com pivot by April 15th wins a YC t-shirt" or something (partner with the websites for prizes, they get free design improvements).

Update: When make a pivot to a specific domain, show me "There's 11 other pivots for this domain" with a link to the list. Make it into something that could be collaborative/social. Let people fork/clone pivots easily ala github.

<comment><AUTHOR> Great suggestions!

I've improved on #1 (added a "Discover Pivots" button that displays the url's as well).

I'm working on #2 and definitely thinking about #3! Showing the number of pivots for a specific domain would also be quite interesting!

</comment></comment><comment><USER7> I'm sure you'll get a little bit of flak for the name, but this is a fantastic idea.

It will make my part-time hobby of sending people completely unsolicited design suggestions even easier :)

<comment><USER8> I am so glad to hear that I am not the only person that does that :)

</comment></comment><comment><USER9> Not quite sure the implementation you have (whether you iframe it or pull content in and redisplay it), but thought of a few suggestions:

1) inject the style tags w/ javascript and it will refresh the CSS content without doing a page reload. We do this on our editors and works well:)

2) Make the text box more coder friendly (allow indents, for one).

Great idea!

<comment><AUTHOR> Will do (both)! Thanks.

<comment><AUTHOR> Both done!

</comment></comment></comment><comment><USER10> Nice project - I made something like this 10 years ago but with editing the HTML that was pulled in instead of CSS. Brings back memories :)

Only note; perhaps you should block out CSS expressions, going to <http://www.csspivot.com/1HDq6> in IE will not be a pleasant experience at the moment...

<comment><AUTHOR> Thanks, will do!

</comment></comment><comment><USER11> Nice project!

After some use, there are some points I'd like to share with you:

* Everytime I save I create a new url. I feel bad, like I'm creating things I'm not gonna use... And this way I can't edit the already saved urls, so if I share one with my friends and then I want to change something, I can't. Maybe you could ask for an optional password before saving.

* If I create a custom CSS, let's say for dribbble, and then I click a dribbble link in the 'frame' in csspivot, the style is not aplied to the loaded page!

Btw, that's what I got: Dribbble Black <http://www.csspivot.com/y036m> (just for ff, srry I have no more time).

Good luck with the project! ;)

<comment><AUTHOR> Thanks for your feedback! Yeah it only applies the css to the selected page -- will think about extending it though!

I'm working on the ability to update existing pivots (if you are a logged in user). Should be online later today.

BTW: I really like your dribble variation -- added it to the selected examples!

</comment></comment><comment><USER12> Cool! I've just done something extremely similar for a school project: <https://github.com/deniszgonjanin/Automagical>

I'll put up a public demo soon. My implementation uses Node, and pulls the page html and css, then lets you edit it. If I can make a couple of unsolicited suggestions:

Right now when you click on a button or a link, it will redirect you to another website. Add a click handler for all elements and then event.preventDefault() so that the link doesn't take you off the page. And second, add a css "outline" style on hover so that the user can see what they're clicking on.

Great work!

</comment><comment><USER13> One suggestion: add a button on your top bar to view the original site (flip back and forth) to compare before-and-after.

<comment><USER14> Yes, this. I found myself constantly removing all the styles to compare the custom version to the original.

<comment><AUTHOR> Yes me too, actually. Will add something to toggle between the original and the custom website shortly (tomorrow or the day after).

</comment></comment></comment><comment><USER15> Well done! I'd be ears to a writeup on how you did it: tech considerations, Ajax, etc.

Super minor nits:

Missing characters <https://skitch.com/rocktronica/rs5nx/csspivot1>

External scripts/CSS brought in with "//" falsely prepended with URL <https://skitch.com/rocktronica/rs5nk/csspivot2>

<comment><AUTHOR> Thanks for the feedback!

The missing characters are because the of unicode decoding in Python. If the content-encoding if not found in the html headers it will replace all unknown characters. I'm working on improving that.

The // is something I can fix right now.

[edit] the // link bug is fixed, and it also allows <https://> links (which i noticed that it didn't work because i pasted in your urls)

<comment><USER16> Have you considered using this: <http://chardet.feedparser.org/> to detect the encoding?

I'm not sure if this helps, but seems like it would.

<comment><AUTHOR> Thank you for the link! Will definitely give it a try (tomorrow)!

</comment></comment></comment></comment><comment><USER17> Brilliant work metachris. I suggest really look forward to expand this project, for budding web designers this seems a excellent tool.

You can really create a community around this, more it goes social the better. A community would really help everyone discuss over the mockup.

And everything else kmfrk already said in his comment.

Good luck!!!

</comment><comment><USER18> This is brilliant,im constantly playing around with ideas using Firebug and then having to take a screenshot and mailing it,now its much simpler. Plus having the site with modified css open in the browser window makes it so much more intuitive for the viewer as opposed to an image. brilliant!

</comment><comment><AUTHOR> I actually got the idea from a comment here on HN a few weeks ago, and had a little time on my hands today and did it.

Here's the obligatory HN link: <http://www.csspivot.com/CH7HJ> (just a green background)

<comment><USER19> You should try to leverage Dustin Curtis' American Airlines remake controversy in some way:

[http://www.dustincurtis.com/dear_american_airlines_redesign....](http://www.dustincurtis.com/dear_american_airlines_redesign.html)

<comment><USER20> Andrew Wilkinson's Zappos "Redesign" which almost consisted of just putting gradients and drop shadows all over the page would definitely be easy with this project too!

<http://www.metalabdesign.com/zappos/>

</comment></comment></comment><comment><USER21> You should remind the user to add "!important" to their styles. I was puzzled for a few seconds.

<comment><USER22> Maybe it would be better to add this automatically, even if it's hidden from the user? I imagine this would match the intent of most uses.

<comment><AUTHOR> Added a reminder inside the title of the dialog. Didn't want to change the user's css -- if they copy it out it might no work then.

</comment></comment></comment><comment><USER23> I love it! Great job!

It is so simple too. I don't need highlighting or anything. Don't make it bloat. Keep the simplicity. This is great.

</comment><comment><USER24> Stylebot is a chrome extension that has similar functionality, with features for easily selecting and manipulating elements on page.

[https://chrome.google.com/extensions/detail/oiaejidbmkiecgbj...](https://chrome.google.com/extensions/detail/oiaejidbmkiecgbjeifoejpgmdaleoha)

<comment><AUTHOR> Yes. But you need to install the plugin to share it -- csspivot.com just let's you send a link to anyone. I think that beats it.

</comment></comment><comment><USER25> I like the idea. Here's how I envision it:

Show me all the existing CSS (with syntax-highlighting) in an editor in a sidebar. Let me modify that or add to it, then share the result. Also, highlight new or modified code somehow. Basically, a save-able, shareable, Firebug editor with diffs.

<comment><USER23> I like the simplicity though. No need to make it busy and bloated. Most browsers already have a Firebug or something on them already (or you can add them yourself). No reason to have two.

<comment><USER26> I agree that there isn't a need to reinvent the wheel, but using it I find myself wanting some firebug-esq capabilities. I ended up just firing up inspector in Chrome, but there may be an opportunity here.

Or integrating something like that could ruin the simplicity of the app.

Still, I like this a ton.

<comment><USER2> He could add is as an advanced feature of sorts - one that isn't immediately visible to the average user.

<comment><AUTHOR> Am definitely thinking about it! Got a pretty good backlog of feature ideas from the feedback here!

</comment></comment></comment></comment></comment><comment><USER27> How much noticeable overhead would be introduced by adding something like xray <[http://www.westciv.com/xray/>](http://www.westciv.com/xray/>); ?

xray or an even simpler implementation being included would make this service even greater.

<comment><USER28> This and using Javascript to refresh the css without reloading would make this killer.

</comment></comment><comment><USER29> Beat me to it :) I decided to have a go at this myself last week and got quite a lot done until the day job interfered. Second comes right after first though, right?

Nice work getting it done!

<comment><USER30> It seems like people say this for every HN post.

</comment></comment><comment><USER31> This would have seriously helped me in a project I am currently doing...

</comment><comment><USER32> I love it the way it is, no need to add noise. Thank you!

</comment><comment><USER33> I have totally hypothetical (but related) question, though: to what extent does a site's CSS need to be changed, for that CSS to be one's own? I'm just not sure to what legal limits people can use your site to save CSS code from other websites that aren't their own? Again, I have no expertise in this particular question, but maybe you want to include a small disclaimer...?

<comment><USER15> Might be a moot point for this app, since it only _appends_ arbitrary CSS and doesn't modify the existing.

That's a good question, though. I bet the WordPress GPL decision might have some relevance to it.

<comment><USER33> Good idea on the _appends_ - who wants to save the entire code for each iteration, rather than just the changes? (hitting myself over head) haha About Wordpress: their explanation seems more marketing-related rather than practical: <http://codex.wordpress.org/License> Maybe going GPL reflects a core change in their business model, now that they're hitched with all the Windows Live blogs?

</comment></comment></comment><comment><USER34> I love this! I looked at doing something similar with node a few weeks ago - you nailed it so much better than my attempt. Congrats!

</comment><comment><USER35> Very clever concept. I also think it would be nice to easily browse edits by having the best css modification bubble up to the top.

</comment><comment><USER26> This is awesome! This will save me a lot of time in communicating small CSS changes across a team. Thanks a ton for building this!

<comment><AUTHOR> I'm happy it will be useful to you -- I was wondering if it would! Drop me a line if you have any feedback and ideas: chris (at) metachris.org

<comment><USER26> For sure! I'll try using it when I have the chance and let you know what I think.

Lightning Edit: and a friend IMs me with questions about CSS. I'm going in.

</comment></comment></comment><comment><USER36> Websites with utf-8 encoding look quite silly.

<comment><AUTHOR> The website works fine with all pages that either

(a) have only ascii chars (b) have any utf8-encoded unicode characters (c) specify the content encoding in the http headers

I'm trying to find a solution.

</comment></comment><comment><USER37> This is awesome. Great job. Please don't feel pressure to lay on many new features. I like the simplicity of the concept.

</comment><comment><USER28> Awesome idea. Right now it's a bit rudimentary but you should look at the flow that Optimizely has for this.

See how they work here: <https://optimizely.appspot.com/edit#url=news.ycombinator.com>

</comment><comment><USER38> I kept trying to tab to format my CSS and accidentally went to the preview. That might be for accessibility, but I'd like to ability to Tab the textarea.

Also Syntax highlighting would be great, but I like the simplicity of it. Don't worry about showing any of the existing css.

<comment><AUTHOR> Thanks! I am working on allowing tabs in the textarea (that's not exactly easy though). Don't know about syntax highlighting.

<comment><USER38> syntax highlighting isn't that important. CSS is a pretty simple language

</comment></comment></comment><comment><USER39> Will be a good tool for design reviews. Just one feedback: Can the popup be aligned to bottom?

<comment><AUTHOR> Let me know how you liked it! I'm also just working on settings for registered users, and that may be one of them.

Now you can also toggle the popup by pressing `, btw.

</comment></comment><comment><USER40> This is pretty creative. Question about the implementation: are you just using urllib to read the contents of the provided URL, then overriding the page's CSS with the user provided CSS?

<comment><AUTHOR> Yes, it works by proxying the request and injecting CSS and the header at the right places.

</comment></comment><comment><USER41> neat. here's how i've been viewing HN through the stylish firefox plugin and my custom style:

<http://www.csspivot.com/PRGZ3>

<comment><AUTHOR> Oddly news.ycombinator.com doesn't load in the iframe all the time -- sometimes I need to reload several times.

</comment></comment><comment><USER42> Woow, I like it. I could actually use it as a simpler replacement for Stylebot. However, I have a feature request: let me change the css styles _without_ changing the url.

<comment><AUTHOR> Is coming today, for registered users!

<comment><AUTHOR> done

</comment></comment></comment><comment><USER43> Great concept. Love it. Adding to my toolkit.

Maybe consider leveraging/partnering with <http://userstyles.org>.

</comment><comment><USER44> Very cool. Any chance you plan to integrate with Firebug?

<comment><AUTHOR> Some kind of inspector would be nice, yeah. The downside is that it adds quite some javascript overhead. I don't know if it's possible to just integrate with Firebug or Chrome inspector.

</comment></comment><comment><USER45> It's ok. Don't go nuts over how you can monetize/expand it yet, work on features and interface.

</comment><comment><USER46> A good idea well designed. Kudos!

</comment><comment><USER47> isn't this already a feature on firebug?

<comment><USER48> That's what i thought. Maybe i'm missing something.

</comment></comment><comment><USER49> AWESOME! I just launched an app with my friends <http://takeastand.com.ng> and I was looking for a way to get design suggestions. I would be glad to get some for my landing page.

PS: do not take a stand becuse it will automatically post to your FB profile and I know the HN crowd will not like it.

</comment><comment><USER50> Nice simple design. <http://userstyles.org/> does something very similar via the very popular "Stylish" Firefox and Chrome extensions. Before I knew about user styles I had a similar idea and made a prototype on <http://perfecttheweb.com>. I have some advice on how to proxy difficult sites like drpepper.com (though perfecttheweb does not implement it) if you're interested. Just gmail craig.quiter.</comment>


Ask HN: How big a server hit is frontpaging HN? - <AUTHOR> Every day a couple of sites I click are down after hitting the HN front page.<p>Can anyone who's been there, done that, give a ballpark for the total hits / hits per second they saw? It would be interesting to know. <comment><USER2> I've had one front page (#8!) to my WP powered blog, one time. It was a huge increase in my otherwise very small traffic. Big numbers (for me). Over the 24 h period it was over 50k page views.

I run this blog on two Linode 1G offerings. One host for MySQL and one for Apache/PHP.

Neither server noticed, I didn't even get a CPU or network load notification from Linode.

So, from my experience, it was a big view-metric spike but resources and response times held in place from a simple, cheap, two-server setup.</comment>


Dijkstra was right – recursion should not be difficult - <AUTHOR> https://blog.angularindepth.com/learn-recursion-in-10-minutes-e3262ac08a1 <comment><USER2> "This task can also be solved using iterative solution, but it's way more complicated because we would have to nest for loops but don't know how deep they are nested. The unknown number of nested loops is a common characteristic of all problems that are recursive in their nature and should give you a hint that recursive solution is required."

Would suggest instead something like

"We could solve this directly by managing our own stack of work done and keeping track of where we are in the problems as we divide them up, but it's easier to take advantage of the fact that the programming language is already providing us a call stack that can do this work for us."

Then, later, you can point out that this also helps with the backtracking solution as the programming language is maintaining the old environments; if you were iteratively managing your own stack you'd also have to backtrack manually.

Because that's how you transform a recursive call into an iterative one, not nested for loops. The general points made in the article still hold up, of course.

<comment><USER3> >Because that's how you transform a recursive call into an iterative one, not nested for loops.

I came to understand recursion through nested for-loops, though, but that might just be a historical accident. In the summer of 1988 I had written a Mastermind solver in Microsoft Quickbasic[1] for the specific case of 4 "pegs". At each guess, I used for-loops nested 4 deep to build a structure representing the possible remaining solutions (for all possibilities of the first peg, check all for the second peg, etc.) Then I wanted to extend it to work with variable numbers of pegs; after spending most of that summer trying to figure out a loop-based solution, I discovered that subroutines could call themselves and it hit me that I could have a function that took the possibilities already computed for a peg, and then called itself with those applied to the next peg.

So I've always thought of recursion as a way to have arbitrarily deeply nested loops.

[1] Believe it or not, it did support recursive functions!

<comment><USER4> Quickbasic was great, fond memories of typing out hundreds of DATA statements for game sprites.

</comment></comment></comment><comment> aaron-santos Recursion shouldn't be difficult, but we write recursive programs using one tool: self-referential functions. That's like trying to write structured programs using one tool - goto.

Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire[1] pioneered generalized recursion schemes and influenced work in Haskell[2] and Scala[3]. It's great having the vocabulary to describe recursion and the tools to elegantly recurse, but anamorphism tends to shut down conversations faster than mentioning the m-word.

[1] - [https://maartenfokkinga.github.io/utwente/mmf91m.pdf](https://maartenfokkinga.github.io/utwente/mmf91m.pdf)

[2] - [https://hackage.haskell.org/package/recursion- schemes](https://hackage.haskell.org/package/recursion-schemes)

[3] - [https://github.com/slamdata/matryoshka](https://github.com/slamdata/matryoshka)

<comment><USER5> I dunno.

I spent some time with that paper awhile back, implementing hylo-, ana-, and cata-morphisms in Python and Joy to be sure I was following along.

I loved it, but I was ultimately convinced that Category Theory et. al. isn't quite as useful for the working programmer as it should be.

What I _did_ find useful is the treatment of recursion in the Joy language. [http://www.kevinalbrecht.com/code/joy- mirror/j05cmp.html](http://www.kevinalbrecht.com/code/joy-mirror/j05cmp.html)

<comment><USER6> Joy is interesting: I never programmed in it, but I had a lot of fun reading it and learning how it works from the documents.

<comment><USER5> To me it seems like it might be a kind of "silver bullet" for programming, due to a number of factors: simplicity and elegance, suitability for partial evaluation and super-compilation, and for parallelization.

I haven't tried to implement a large system in it yet though. If I get the time I hope to re-implement the Oberon OS using Joy.

</comment></comment></comment></comment><comment><USER7> This article touches on some good points. In particular, the part about trusting that the function will do the right thing is something that people who already understand recursion take for granted but is extremely crucial. However:

"Let's tweak our sum function a a bit: ... That's it."

I really dislike articles that earnestly try to convince the audience that some subject which many find extremely difficult to understand is actually very simple. My impression is that the intent is to help people who lack the confidence to engage with the topic, but in my opinion the exact opposite effect is achieved. At that point in the article, nothing about recursion had been explained and it's not reasonable to expect someone who previously did not understand recursion to read that section and come to the conclusion "that's it!" Instead they'll be sitting there, extremely confused by something which they're being reassured is actually quite simple. This is not going to help their confidence.

So while I appreciate the author's intent, I think that someone who is struggling to understand recursion might leave this article worse off than when they started. And I wish this trope would disappear from tutorials.

<comment><USER8> I auto-ignore tutorials that say stuff like, "X made simple". It's almost always trying too hard to make a genuinely difficult subject easy, thereby obfuscating the topic more.

<comment><USER9> I learned long ago that books titled like "advanced X" will be a very simple book on X suitable for any layperson with basic knowledge. Books titled "introduction to X" or "elementary X" will be extremely difficult.

<comment><USER10> I have not yet seen books titled "advanced X" that are actually grokkable, but my university courses called "introductory X" were exactly the hardest ones.

<comment><USER11> In general, laying foundations to any broad topic is hard! I imagine knowledge to be like pyramids, where the bottom support the top. But to support a tall pyramid, a large bottom is required. Thus, we get these obscenely difficult 'intro' books...

</comment></comment></comment></comment></comment><comment><USER12> You don't really understand how difficult recursion is until you've tried to teach a bunch of programming newcomers the concept. A few get it quickly, but for the rest all the "think of it like ..." suggestions don't really help. It's a concept that everyone seems to have to learn through practice (as the author implies). I fell into the trap that if I only explained it clearly enough I could make it easy for others. Everyone learns it their own way and you just have to give students enough opportunities to practice for them to get it. I don't disagree with Dijkstra that the concept shouldn't be difficult, but I do not believe there are any easy paths to the concept for most.

It's one of the most interesting learning processes in that once you get it, it feels almost as simple as a for loop or simple math. But until you get it it feels like the most opaque, impenetrable wall where 1+1 != 2.

Side note, recursion would be slightly easier if the concept of a base case were applied to _all functions_ as preconditions. The idea of a base case really has more applicability than just in recursion, it's just that we don't call it a base case in other situations.

Recursion is also interesting to implement when doing TDD. It comes in a refactoring step, of course, but you don't have to think about the base case(s) because they've already been done. Again, not suggesting this is helpful to a newcomer struggling, but is just an interesting process.

<comment><USER13> Can you expand on "base case for all functions"?

I'm having a hard time figuring out a base case for say calling toString on an object, or incrementing an integer.

<comment><USER14> > I'm having a hard time figuring out a base case for say calling toString on > an object, or incrementing an integer.

In both cases, we can special-case the "zero" of the domain. For example, toString of an object without any attributes would return '{}', while incrementing the integer zero would return 1.

I'm not sure about the usability of the latter in an iterative approach, but the former could definitely be used as the basis of an iterative algorithm that traverses all of an object's attributes.

</comment></comment></comment><comment><USER15> > This is because a recursive sub-function never solves the exact same problem > as the original function, but always a simpler version of an original > problem.

This isn't always true. There are plenty of recursive functions whose purpose is merely to climb until a condition is met that there are no more rungs in the ladder.

Recursion is difficult because it isn't just taught, it is mythologized as the potentially infinite source of a one's love for programming. If teachers similarly mythologized the "switch" statement I'm sure they could confuse the topic of conditionals just as easily.

<comment><USER16> >> This is because a recursive sub-function never solves the exact same problem as the original function, but always a simpler version of an original problem. > This isn't always true. There are plenty of recursive functions whose purpose is merely to climb until a condition is met that there are no more rungs in the ladder.

What do you mean here? What is the ladder in your analogy? The stack? Is the "a condition" that the stack has reached its limit or that you have reached a base case?

If computing f(50) requires computing f(50), it will never end. Likewise if you have a base case at 0, if f(50) requires computing f(51), it will never end. You must solve a problem closer to your base case than the original problem.

> Recursion is difficult because it isn't just taught, it is mythologized as > the potentially infinite source of a one's love for programming. If teachers > similarly mythologized the "switch" statement I'm sure they could confuse > the topic of conditionals just as easily.

I don't think that recursion is mythologized. It allows you to express the core idea of the algorithm really succinctly.

For example defining the Fibonacci sequence just requires the beginning numbers and the rule for progression.

        fib(n):
          if n = 0 or 1: return 1
          return fib(n-1)+fib(n-2)

It is much simpler than the iterative solution (though generally being inefficient).

Often the simplicity gained by using recursion (if you are comfortable with it) makes it possible to understand algorithms you could not understand the iterative form of.

Also, recursion is simply more powerful than just while or for loops (you need stacks as well). And when you add stacks into the mix, iterative programming can get very confusing.

<comment><USER17> Simpler than the iterative is hard to argue -- it's closer to a strict mathematical definition but the iterative version can also be setup very simply too.

To say one is more powerful is really false. I think recursion is great, and for some situations it should be the go to method, but anything you can write iteratively you can write recursively and vice-versa.

<comment><USER16> > To say one is more powerful is really false. I think recursion is great, and > for some situations it should be the go to method, but anything you can > write iteratively you can write recursively and vice-versa.

I mean powerful in a strict theoretical sense. Without using a way to freely allocate arbitrary memory, recursion can compute things loops cannot. The ackerman-peter function is an example.

Loops however can be trivially converted into functions.

Therefore because loops can be converted into recursive calls and recursive calls cannot always be converted into loops. Recursion is more powerful.

</comment></comment></comment></comment><comment><USER18> Practice makes perfect, I think most learners can get comfortable with recursion as they use it to implement simple recursive solutions (Fibonacci, tree traversals..etc). Over time it becomes quite natural to recognize when and how to use recursion.

One source of confusion that most learners have stems from the seemingly mysterious way that intermediate results are kept track of. This is one of the downsides of not having experience with low-level programming. If you're familiar with assembly language programming and understand how register contents are pushed/poped on/off the stack between sub-routine calls then it is easier to understand what is happening behind the scenes.

<comment><USER19> > If you're familiar with assembly language programming and understand how > register contents are pushed/poped on/off the stack between sub-routine > calls then it is easier to understand what is happening behind the scenes.

Assembly programming in college is exactly what made recursion really click for me!

<comment><USER20> I taught myself to be comfortable writing recursion through practice, practice, and practice, but I feel like things clicked at an entirely different level when I could trace something in assembly and see that the arguments were actually being stored in _different_ locations as the stack pointer increased.

</comment></comment></comment><comment><USER21> Anything that is self-referential is hard. I remember when we covered proof- by-induction in HS math. There was a significant fraction of the class that did not believe a given proof was sufficient.

If you can't assure yourself of the correctness of a fairly simple recursive function that is given to you, then composing one yourself is going to be nigh impossible.

[edit]

From the article: _Instead trust that it returns correct sum for all elements of an array a[i]_

This is exactly the point where many people get hung up. They cannot proceed to reading the next line until they understand how the recursive call works. They are unwilling to trust that the function works as advertised, and cannot shift gears to continue past that. In my experience, telling them to "just trust it" and such seems to not help much.

<comment><USER22> > _In my experience, telling them to "just trust it" and such seems to not > help much._

Just call that recursive function something else. Give it some other name, and say that we must take it for granted that this other name is a function which is already debugged and tested by another team of programmers:

       (defun our-member (item list)
         (cond
           ((atom list) nil)
           ((eql item (car list)) list)
           (t (member item (cdr list)))))

Here, we rely on _member_ , a standard function in the language already, and so there is no recursion.

We first convince ourselves that what we have works.

And then, final step: since what we have works, it means that _our-member_ is a correct implementation of _member_ , which means that the two are equivalent. Equivalent functions are substitutable. And so we can just perform that substitution: replace the _member_ call with _our-member_.

By the way, it occurs to me that Hofstadter's _Gödel, Escher and Bach_ might be a good source of ideas on how to deal with presenting and teaching self- referential topics.

<comment><USER23> _Give it some other name, and say that we must take it for granted that this other name is a function which is already debugged and tested by another team of programmers_

That seems like it's "begging the question" \--- as in, "if there's already a function written to do what I want, why do I need it to write one to do it...?"

<comment><USER22> But that problem is present in virtually all homework in CS.

Someone already wrote a Celsius to Fahrenheit conversion function, a simple ray-tracer, a quicksort, a toy Lisp, a text-file-based simple inventory system, etc ...

We could make up a back story about this to give it real-world plausibility: yes, the function is already written, but it's in an expensive, proprietary third-party library which we cannot ship without paying royalty fees and being bogged down with various inconvenient restrictions.

<comment><USER24> But you don't call a library bubble sort function _inside your own implementation_ of bubble sort!

<comment><USER21> My idea for teaching it is to start with just a function that calls the library function:

       (defun our-member (item list)
         (cond
           (t (member item list))))

Now everyone in the class should quickly agree that this function works. Next say "our goal is to write our own implementation of member, so we will handle one special case at a time until we don't need to call member anymore"

so step 1:

       (defun our-member (item list)
         (cond
           ((atom list) nil)     ;; if it's not a non-empty list, it can't be a list containing item
           (t (member item (cdr list)))))

step 2:

       (defun our-member (item list)
         (cond
           ((atom list) nil)            ;; if it's not a non-empty list, it can't be a list containing item
           ((eql (car list) item) list) ;; if the first element of the list is our item,
                                        ;; we have a match and return the whole list
           (t (member item list))))

step 3:

       (defun our-member (item list)
         (cond
           ((atom list) nil)              ;; if it's not a non-empty list, it can't be a list containing item
           ((eql (car list) item) list)   ;; if the first element of the list is our item,
                                          ;; we have a match and return the whole list
           (t (member item (cdr list))))) ;; we already know that the first item is not a match, so we can just run
                                          ;; member on the tail of the list

And now demonstrate that replacing member with our-member will still be correct.

[edit]

derp _(atom nil)_ => T

</comment></comment></comment></comment></comment></comment><comment><USER25> When I was a kid, we learned the principle of mathematical induction in algebra class. That made recursion seem easy.

As for the limitations of recursion on any given system, that's easy to learn because... kids will be kids. Practically the first thing I tried with recursion, ended up with the system operator yelling at me, and learning what a core dump looked like.

</comment><comment><USER26> If you want to really delve into recursion, I recommend to learn a logic programming language like Prolog.

Interestingly, Prolog programs are often efficient _and_ general because, due to the power of unification, Prolog programs are more often tail recursive than functional programs.

For example, we can define a relation called "append" in Prolog as follows:

        append([], Ls, Ls).
        append([A|As], Ls, [A|Rest]) :-
                append(As, Ls, Rest).

In Prolog, recursion naturally arises by considering the inductive definitions of terms. For example, you can read the second clause as " _If_ it is the case that append(As, Ls, Rest) holds, _then_ it is also the case that append([A|As], Ls, [A|Rest]) holds".

Note that such cases are _not_ naturally tail recursive in Lisp, for example, because in languages that do not support unification of logical variables, there is one additional call of "cons" after the recursive call to construct the result. Also, the Prolog version is much more general and can be used in several directions! For this reason, "append" is not even a good name for such a relation, because it already implies one particular direction.

</comment><comment><USER27> The two biggest problems with recursion in practical use is that not all compilers can properly handle optimizations around tail calls, and not all TCO capable compilers can handle all tail call cases.

If either case occurs, you run into the issue where you will seemingly randomly blow out your stack space when your list is too long, or your tree too deep. Then you have to fall back to a non-functional idiom (or do some other magical incantations to avoid function stacks, like Clojure's `loop` special form).

I think recursion is a great tool, but it's so poorly implemented in so many languages that it's simply too dangerous to use.

<comment><USER28> If recursion could be tail-optimized, it's usually better just to write iterative `white`, unless you can't use mutable variables. The interesting recursion which can't be trivially replaced with loop is not tail optimizable.

<comment><USER29> You can implement state machines as a set of mutually-recursive functions with one state = one function. Works very well, is tail-recursive and not trivially replaced by loops.

<comment><USER30> It is quite replaceable if you represent the actual graph as a data structure with terminator nodes. No need for more recursion - the data structure is recursive, but algorithm is not.

It is even easier to prove bounds. You get to prove correctness for cycles (if applicable), connectedness of the graph and whether a terminator node is connected to all acyclic arcs. (Latter can be a trivial proof on the constructor.) Just like for recursive implementation except proving the cycle lemmas is easier.

<comment><USER29> Interesting. In the implementation as function you trivially can give different states differently typed arguments.

How do you do that in the version you sketch?

</comment></comment></comment></comment></comment><comment><USER31> Here are the steps in my recursion experience:

1) teenager reading a pascal book: clueless

2) college C course: imperative "print tree", easy

3) advanced compiler: more sophisticated environment thingies, clueless again

4) CGI quadtrees: want fully recursive solution but chokes

5) rediscovery of lisp: recursion wannabe

6) cons-based lists fundamentals: linear converging recursion is everywhere, pattern is easily understood and memorize, everything makes sense

7) FP and lispy combinatorics (treerec, partition, countdown): it seems like point 2) but something is different now.. deep recursion involves self closing types. It's not just repeat until and do not care about what happens you'll fix it down the road. It HAS to make sense, and to typecheck right away.. recursive steps will be used for the previous level it has to fit logically.

If one reaches that level your understanding shifts entirely. Recursion is it's own solution, it's absurd but it's a deep reference point to solve problems since you can assume something that doesn't exist and see if it holds..

Now you get to rediscover math proofs and a lot of late HS and college math. Finally something I wanted to know and recently found out about, list recursion are only a linear pattern of recurrence. It's one dimensional and often on an easy to proove converging variable (cdr + nil?, natural dec + zero?). There are n-dimensional patterns, and litterature about it. I can't recall the books but I'll dig for it.

And finally, Turing among other tried to rethink imperative programs as one big while modifying one big vector variable (aka system state) and proof that this n-dimensional vector could only have some sound values and would reach terminating ones. (I think it's called linear ranking ..)

Cheers

<comment><USER30> You mean a deterministic state machine? Sheer number of states makes the approach less than useful.

Tree recursion is often also easy to prove. Kd-tree operations (incl. quadtree) are tree recursion. The only problem with it may be cache locality.

The only trouble is you have to prove you're walking the tree in one direction for correctness. To prove that in a row system rewrites some pretty interesting monads.

It greets even trickier once the recursion tree is uneven or lopsided, like in R-trees. Then you get to think about upper bounds etc.

</comment></comment><comment><USER32> Some years ago I had problems with recursions too, because I always had some edge cases which made my functions go wild (endless loops). But one day someone told me, that most recursive programs can be written into the skeleton below:

      function a(){
        if(/* Termination Condition */){
          return /* Special Element */
        } else {
          /* Recursion: e.g. a + a */
          return a() + a()
        }
      }

Since that day I love recursions.

<comment><USER30> This is tree recursion that is not well optimized by modern compilers. AS opposed to tail recursion.

<comment><USER21> It is very rare that the tail-recursive form of a function is more readable than the non-tail recursive form. I find tail-recursion intellectually interesting, but of little use for actual programming.

Contrasted with tree-recursion where the code is often so pithy that its correctness is obvious (assuming you understand recursion).

<comment><USER29> Tail recursion sometimes comes up naturally. It's essentially a goto with parameters. Thus it comes up where goto is also (at least borderline) useful, eg implementing state machines.

<comment><USER21> I almost added a parenthetical after "rarely" to the effect that state- machines are the one exception I've encountered.

</comment></comment></comment></comment></comment><comment><USER33> I admit this is complete speculation on my part, but I can't imagine it helps to combine recursion with C-style for-loops.

Both pieces of advice from the article: "trust the recursive function" and "don't try and trace the execution" seem easier if the control flow is simpler.

Compare:

        function sum(a) {
            let result = 0;

            for (let i = 0; i < a.length; i++) {
                if (Array.isArray(a[i])) {
                    result += sum(a[i])
                } else {
                    result += a[i];
                }
            }
            return result;
        }

        function findCeo(employee) {
            let boss = employee.getBoss();
            if (null == boss) {
                return findCeo(boss);
            }
            else {
                return employee;
            }
        }

<comment><USER34> I have a problem with the second example. An attribute to track the title of an employee would solve the problem of finding the CEO and any other type of employee, this should not be done with recursion. If recursion is such an important concept we should have real-life examples of it being employed properly to lean on.

Also am I missing something or does your findCeo function return the employee when they have a boss and recurse when they have no boss? Seems like this just returns the employee in most cases and infinitely recurses for the CEO who presumably has no boss.

<comment><USER35> I think the author made a typo/bug. The function will crash on a null.getBoss call as soon as it found an employee without a boss.

<comment><USER33> Correct.

</comment></comment></comment></comment><comment><USER36> The first problem in the OP is ill-typed, so if this was intended to help people get a good grasp on recursion, that may be counterproductive.

I never had any problem using recursion, but my ability to reason about it at an abstract level is due in large part to the excellent paper "Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire", which covers various abstract approaches to dealing with recursion schemes. [https://maartenfokkinga.github.io/utwente/mmf91m.pdf](https://maartenfokkinga.github.io/utwente/mmf91m.pdf)

</comment><comment><USER37> I think part of this can be explained by the way recursion is handled on major platforms. Even something like Python which has some functional leanings is prone to stack overflows with deep-ish recursion without hacky workarounds. Once the tools most people are using are more recursion friendly, I think we'll see it become more mainstream. I think JS has TCO now, at least on Node, which is a huge step in that direction.

<comment><USER12> Safari is the only browser that has TCO so far. V8 has it listed as a blocking bug:

[https://bugs.chromium.org/p/v8/issues/detail?id=4698](https://bugs.chromium.org/p/v8/issues/detail?id=4698)

Unless I'm reading that wrong, TCO was pulled as even invokable by a harmony flag because it was so broken to be a security risk.

I wonder if there are any explanations other than focus or priorities as to why it appears to be harder to implement in Chrome than it was in Safari/webkit.

Anyway, since it's not in V8 that means it's not in node right?

<comment><USER37> I guess not, that's pretty disappointing. Hopefully we'll get it eventually, though.

</comment></comment></comment><comment><USER38> To understand recursion get "The Little Lisper" or the later book "The Little Schemer". To know when not to use recursion and use iteration instead, look at "Algorithms + Data Structures = Programs" and finally, you can delve into the mathematics of primitive and non-primitive recursive function with "Recursive Functions in Computer Theory".

Good reading to all.

</comment><comment><USER39> For one it's not handled well by many languages, expensive stack cost, not tail call optimized, max limits on stack, ... It would be nice if you could write recursive algorithms in code and be sure it ran as well and efficient as when you do it manually with for loops and separate stack data structures.

<comment><USER40> Not to mention the debugger. Recursive loops create huge traces that are difficult to follow vs an equivalent for loop.

<comment><USER41> That's a feature, not a bug, in my opinion. Recursion preserves information about the function's execution. The problem is debuggers being too dumb to detect it and present it well.

</comment></comment></comment><comment><USER29> Imperative programmers learn special purpose constructs like loops that only work in simple cases. But since they are so wedded to them, they only reach for the more general tool in more complicated cases. Thus they blame the general tool for the complication.

Just do away with the special cases, and us eg functional calls as the basis for your control flow needs. Then recursion becomes simple.

If necessary, one can introduce loops as a special case later---if working with legacy code or languages that don't properly support function calls. (Eg languages without first class functions and tail call optimizations.)

</comment><comment><USER42> Recursion is hard, but it is a fundamentally great tool.

If I talk to someone who doesn't understand programming, they can usually understand the if and for statements that you might find in food recipes or in legal contracts.

But almost nowhere outside mathematics and computer science (and certainly not as common as recipes) do you come across recursion.

It's mentally hard to think of a problem so that each step gets simpler.

Solving the towers of hanoi is not straight forward, I can't follow it at the speed that I can read as I could with basic math, I have to really think if what they are suggesting works and how does it work.

However when you get to solving hard problems, recursion really helps. I know from having spent hundreds of hours with interview questions. Bugs can make a problem go from taking me 30 minutes to 4+ hours. Where as using recursion and other functional programming concepts, once I got to the solution it would usually be bug free. So whereas it might not be as fast, I would be more confident in my final answer.

</comment><comment><USER43> I love the Erlang way of dealing with this:

      % Problem #2

      % Each new term in the Fibonacci sequence is generated by
      % adding the previous two terms. By starting with 1 and 2,
      % the first 10 terms will be:

      % 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

      % By considering the terms in the Fibonacci sequence whose
      % values do not exceed four million, find the sum of the
      % even-valued terms.

      fibsum(_N,M,L) when M >= L -> 0;
      fibsum(N,M,L) when M rem 2 =:= 0 -> M + fibsum(M, N + M, L);
      fibsum(N,M,L) when M rem 2 =:= 1 ->     fibsum(M, N + M, L).

      problem_2(L) -> fibsum(1, 2, L) .

      problem_2_test() -> ?assert(problem_2(100) =:= 44).

      problem_2() -> problem_2(4000000) .

(When familiarizing myself with a new programming language I usually work through several 10's of the project Euler problems, that way I only have to learn one new thing.)

<comment><USER44> Name your variables.

</comment></comment><comment><USER45> Is recursion difficult? I remember when we did our first recursion in the first year of CS and our professor told us it sould be hard. Then she went on a rant about divide and conquer which made little sense and eventually got to the bit about calling yourself until a criteria.

I think most of us thought it was the easiest part of that year.

<comment><USER46> I think recursion as an implementation is easy; recursion as a concept is hard to understand if you are just starting to learn. I think part of it is getting your mind to accept the notion that a thing can know of itself before itself has been fully defined.

<comment><USER47> I suppose it is easier if you learn proof-by-induction first in a math class.

</comment></comment></comment><comment><USER48> Recursion is _different_. Almost in exactly the same way that geometric proofs are different.

As such, it requires different ways of teaching.

I have used "The Little Schemer" (even back when it was called "The Little Lisper") to teach lots of "non-programmers" (I hate that description) how to do recursion.

<comment><USER49> _The Little Schemer_ is really probably the best way to teach recursion.

</comment></comment><comment><USER19> I don't think telling people who find a subject difficult that it is easy is very convincing.

Recursion seems fairly straightforward to me if you think about it in terms of how it's typically implemented (the stack and jumps), but that's not quite the mathematical way of thinking about it, I suppose.

</comment><comment><USER50> I found this HN thread to be quite useful to this conversation: [https://news.ycombinator.com/item?id=14949392](https://news.ycombinator.com/item?id=14949392)

</comment><comment><USER51> Switching to using Erlang full time, closures and functional aspects (returning a function from a function) and recursion was a lot harder for me to grasp than the isolated processes and message passing.

It took a few months to get my head around it, but once you do, it becomes so obviously simple and easy that you start thinking in it directly. All of the sudden having to write "for(i=0;....)" seems eeky and cumbersome when going back to a language which doesn't handle recursion as well (where it will blow the stack for example).

<comment><USER52> > It took a few months to get my head around it, but once you do, it becomes > so obviously simple and easy that you start thinking in it directly

This is exactly where functional programming shines, in my opinion. It gives you the ability to write your program logic directly, rather than use mechanical constructs (e.g. for loops with indexes) that _behave_ as some logical construct.

The "for(i=0;...)" construct is something I'd give to a machine for the purpose of execution, whereas the logical description is how I'd explain it to a human — and the former can be deduced from the latter.

</comment></comment><comment><USER53> The concept of recursion was easiest to grasp by watching a kid do the maze on a placemat at a restaurant. You go in a line until you find a dead end, then backtrack. Repeat the process until you reach the goal. Each intersection where you make a decision is your function call, and each backtrack is the return result.

<comment><USER54> Which is an odd example, since maze solving by recursion typically requires something like the Zipper data structure. And... no, that is not necessarily easier to deal with than just using a standard stack and jotting down your work as you go.

<comment><USER53> I was thinking the classic case of a 2D array representing the maze: value of 1 for walls, 0 for space, 2 is the goal. Recursion of it is simple:

Function Solve(x,y,dir) {

      Solved = false

      If (maze[x,y] == 2) {
        Print "goal at "+x+","+y
        Return true
      }

      If ((dir != 3) && (maze[x,y-1] != 1)) { solved = Solve(x,y-1,1) }
      If ((!solved) && (dir != 4) && (maze[x+1,y] != 1)) { solved = Solve(x+1,y,2) }
      If ((!solved) && (dir != 1) && (maze[x,y+1] != 1)) { solved = Solve(x,y+1,3) }
      If ((!solved) && (dir != 2) && (maze[x-1,y] != 1)) { solved = Solve(x-1,y,4) }
      If (solved) {
        Print "path "+x+","+y
      }
      Return solved

}

The pseudocode will search the maze, find the exit, then print its location followed by the path to get there in reverse order. Nothing complicated, but shows off the statefulness of recursion without needing anything else.

<comment><USER54> And this is one where I find myself falling back onto (ironically, per the thread?) Dykstra's algorithm. Which I did not learn recursively. It makes much more sense because the "path" that I am recording is a first class thing in the algorithm and not a byproduct of the implementation.

</comment></comment></comment></comment><comment><USER55> I liked this. It reminds me of proof by induction. I recall my teacher telling us it was one of the harder concepts, and thinking, "this sounds just like recursion, and seems pretty natural." I think if she had taken away the scary introductory language, students would have been less afraid of it.

</comment><comment><USER56> Recursion only begins with the notion of mutual recursion. Transforming imperative loops into recursion (with the constant-space accumulation pattern and TCO) is a nothing-special mechanical operation. Recursion really shines in mutually recursive algorithms, like the famous Hanoi Tower solution.

</comment><comment><USER57> I think a good analogy to teach recursion are humans, or really any living thing, since they too are functions that call themselves. That is, each time you create a new human, it's function is to create a new human, and so on ad infinitum.

</comment><comment><USER58> IMHO, the first problem of summing a generalized array of numerical elements is not best solved recursively. I suggest sum(flatten( )) is better and uses less overhead. The subsequent problems under discussion more strongly require recursion.

</comment><comment><USER59> well I do not think recursion is difficult. but I think doing it in a tail- called optimised way, can sometimes be tricky (especially in compilers or node traversals). that's why more and more cps style recursion comes into place more than often. heck even scala has a way to do cps style tail calls: [https://www.scala- lang.org/api/current/scala/util/control/Ta...](https://www.scala- lang.org/api/current/scala/util/control/TailCalls$.html)

</comment><comment><USER60> Relevant older comment of mine: [https://news.ycombinator.com/item?id=11152492](https://news.ycombinator.com/item?id=11152492)

</comment><comment><USER61> Didn't read the article. I usually don't have trouble with recursion, however lately I have started to avoid it more and more often. It is true that linear solutions usually look more complex. However in my opinion they also allow better reuse of local variables. Their complexity also depends on the datastructure. Designing a linear datastructure for nested problems is sometimes possible and can allow simple non-recursive solutions which I find more elegant.

<comment><USER11> You'll find that since problems are notoriously hard to do iteratively, unless you effectively simulate recursion via a stack.

</comment></comment><comment><USER62> The Little Schemer is what made me fully comfortable with recursion. It's an amazing teacher.

</comment><comment><USER63> "There's no such thing as a bad student. Only a bad teacher." \- Mr. Miyagi

</comment><comment><USER64> The easiest way to learn recursion imo is by limiting the domain.

For example, we have a thing called a number:

x

how do we indicate the next number? Well we need a new symbol to distinguish one number from another.

Lets use a marker called prime:

x, x`

Great, now we have two numbers. But let's get a third number. How could we indicate that? Well we could introduce a totally new symbol, like a 'q'.

x, x`, q.

Well that works. but we seem to have just arbitrarily chosen q. There's no immediate obvious aspect of q that lets us know what the next symbol should be if someone asked us to add yet another number. We have three distinct number things but no clear unified way to proceed... But wait, before we took some number x and added a prime to it: x->x` which got us a separate symbol, aka a different number. What if we just do that again but this time with our second number: x`->x`` Great. Now we have three numbers, and we can always use the same rule "add a prime mark" to generate the next symbol, so long as we input the last symbol into our rule:

x, x`, x``

We also wind up with neat little equivalences:

x`` = x`, x = x, x, x

or if our prime operation is a function:

x`` = prime(prime(x)) = prime(x`) = x``

so x``, is just the result of prime of prime of x.

So on and so forth until infinity.

What makes recursion harder to work with in CS is that, unlike summation, you _can 't_ go to infinity--you need to terminate the operation eventually if you actually want it to do anything. Because of this and because of the fact that our inputs are not little units like numbers but are usually data structures which require more rules to recurse over, recursion in CS is tightly and innately coupled with pattern matching and the notion of defining bottoms or terminating cases which is not the case for operations in mathematics where we do not care about terminating because it just encodes the rule and isn't actually meant to do anything, and when we do need to do something with it we limit it by deciding when to stop (so I guess some neuron firing is the bottom/terminating case for human operations?).

Recursion in CS is also additionally difficult because we have to worry about how the computer stores the results of each recursive application and feeds them back whereas, kind of like a high level language, our brain just manages all that for us when we do math. Also note that we take huge shortcuts with things like Arabic numerals--which are an incredible advance in efficiency but probably obfuscate the recursive roots of mathematics for most learners (e.g. you just learn that some symbol 2 and some symbol 2 is another symbol 4 and not that these are encapsulating successive applications of the same rule over a set of arbitrary symbols--I mean, your brain knows this deep down--that's why it works, but it makes it difficult to immediately comprehend that it is in fact recursive unless people have pointed this out to you--at least that was my experience; I may have just had bad teachers).

</comment><comment><USER65> "This article is aimed to introduce and explain a number of topics and ideas that will help you when practicing recursive problems."

I know I'm not supposed to shit talk the article. I know someone spent a lot of time making it for me and others. However, we've gotta move forward as a community. We have to raise the bar. We have to stop this nonsense.

There is an issue here greater than recursion. I know that's bold of me to say, but I'm serious. Programmers need STOP fucking telling people that they can explain something that requires practice to understand. You cannot learn multiplication from reading a blog post. It has to be drilled into you over and over again. And only after it's been drilled into you what numbers are, what addition and subtraction are, and what carrying and borrowing mean. You learn this over the course of YEARS not 5 minutes reading some shitpost on the internet. Recursion is just like math. It has to be drilled into you. I had zero understanding of this for YEARS. And then I picked up a book that drills recursion into you. Only after writing function after function (functions essentially identical to one another in structure), was I able to understand the IMPORTANCE of recursion. Not by thinking about it, or reasoning about it, by actually doing it, over and over again. Recursion can be explained in 10 seconds. I'll do it right now. Recursion is when a set of instructions starts over from step 1. Or for us programmers, a function which calls itself. Bam. all you need to know about recursion. Guess what. It's not enough to understand what multiplication is, you actually have to be able to use it. You actually have to be able to use recursion. Explaining why multiplication is important is frankly retarded. This post is frankly retarded. STOP pretending that you can explain in 5 minutes what took you months and years to understand. STOP. All you do is make people like me think they're dumb for not getting it. I'M SMARTER THAN YOU! But it took me months of ACTUALLY WRITING RECURSIVE FUNCTIONS to realize HOW FUCKING DUMB YOU ALL ARE. Stop fucking telling people you can teach them calculus in 5 minutes. Stop telling them that all it takes is this one clear explanation. It doesn't! It takes actual work. Fuck the guy who wrote that post. You have no idea how many years I wasted thinking blog posts like this were how to learn. If you don't get why recursion is a big deal, do yourself a favor and forget everything you read in that post, grab a pencil, some paper, and a copy of the Little Lisper. Email me in 6 months when you're finished, so that you can thank me for being the only one to tell you the truth about recursion.

</comment><comment><USER66> Recursion isn't difficult. I never had a problem understanding it. Stepping through a recursive function with a debugger that shows you the current stack trace should make it plain as day how it works.

Not trying to toot my own horn or try to make an appearance on /r/iamverysmart, but where are people struggling when it comes to understanding recursion?

<comment><USER67> Third year CS student weighing in:

I never had trouble, but a lot of my friends really did. I helped a lot of them, and I generally got the impression that the ones that really struggled were the ones that fundamentally didn't understand how function calls and returning values truly worked.

Like if you just were to do something like `foo(bar(yuk(asdf(value)))).bind(reck(something)).toString()` (not that this is a reasonable example), they'd have trouble tracing the order of execution. This was freshman year, so I'm sure they're all fine now, but CS is so abstract that every new concept has a barrier that can be surprisingly hard to overcome. Things like recursion or `this` may seem obvious now, but they weren't always.

<comment><USER66> > I generally got the impression that the ones that really struggled were the > ones that fundamentally didn't understand how function calls and returning > values truly worked.

You're probably right.

I don't think in the entire time I was in school, we were shown a debugger and how to read a stack trace or step through code. In one of my classes, we might have glossed over it for a couple minutes, but generally there was very little real debugging shown. It was always "Oh, we didn't get the expected result, let's look harder at the code we've entered." My school may have offered a class on debuggers as an elective or maybe a Masters level class.

Really though, using a debugger, even if it's just the one in Visual Studio, should be included in the first-year classes. By the end of your first year, you should be able to know what a stack trace is and what it's telling you.

<comment><USER68> I remember one of the books in my algorithms class actively discouraged debuggers and advocated for harder reasoning and inserting print statements. Their reasoning was that programmes are too quick to reach for a debugger rather than really understanding their code. I'm still not sure how I feel about that.

<comment><USER11> If you were trying to learn math, your shouldn't be reaching for a calculator everytime when there's a difficult arithmetic problem.

A debugger is the same. Use it when you've mastered skill of desk checking code, and understand how to make hypothesis about where bugs might be and binary search with prints to debug.

When actually developing software, you then reach for the debugger for convenience. But the skills learnt above is still very useful, and is in fact a good way to learn how to problem solve.

If you only ever relied on a debugger, it'd be like only knowing how to use calculator and no mental arithmetic.</comment></comment></comment></comment></comment>


Russian Android Trojan Acecard Compromises Online Banking - <AUTHOR> http://www.blog.cloud-optimizer.com/2016/02/24/russian-android-trojan-acekard-compromises-online-banking/ <comment><AUTHOR> I'm not especially great with security, but if this is true it sounds pretty serious. Surprised a spot check in HN Search didn't come up with anything related..?</comment>


Ask HN: Looking for a 'how to hire' type-ish thread from a githubber - <AUTHOR>

I read a post discussing good hiring techniques on Monday (11/7) between 5:30 and 9:00 by a githubber and have been looking for it too long now -- hoping somebody can remember some better clues about it then I can .. please dont waste time digging for it.. thats what i will be doing. just post if you can remember it off the top of your head.. thank you <comment><AUTHOR> found it - [http://blogmyquery.com/index.php/2011/11/knyle-style- recruit...](http://blogmyquery.com/index.php/2011/11/knyle-style-recruiting/)</comment>


Ask HN: Too old for Y Combinator? - <AUTHOR>

Seriously, who's the oldest co-founder in any Y Combinator company? I'm pretty sure we would be the oldest, should I be worried? ("Look out, here come the graybeards!!")<p>Old thread, here: http://news.ycombinator.com/item?id=248811 <comment><USER2> You certainly don't have anything to worry about. There is nothing age specific about YC.

I am pretty sure that I remember pg mentioning in a previous thread on this topic that there have been YC founders in their 40's and 50's.

The age range in our batch (w2010) was 18 to late 30's with the average probably being somewhere in the middle 20's.

</comment><comment><USER3> My startup is made up of a 26, 28 and 63 year old and we are going to apply to YC Summer 2011.

The 63 year old is my father. He's pretty tech savvy and understands our target market very very well. On top of that he founded a company in the early 90s back when founding a company on someone else's dime was a much more challenging endeavor because of the amount of cash involved.

</comment><comment><USER4> In this case, the tried and true hippie wisdom still applies: "Age is just a number, man." Older founders can be energetic and adventurous, and young founders can be mature. Based on your profile info, you guys seem pretty youthful.

Also, with the Yuri Milner funding injection to YC, there will likely be more "graybeards" in the future.

</comment><comment><USER5> _I'm pretty sure we would be the oldest_

FWIW, I'm 37 (turn 38 in July) and I'm looking forward to possibly applying to YC in the future. So yeah, there are a few of us older guys out there still dreaming the startup dream. I wouldn't worry about the age thing if I were you. It's just a number.

</comment><comment><USER6> Y Combinator does (or at least did in the past) ask for the founders' ages on their application, so it must be incorporated into their decision making process somehow (not saying negative or positive, but if it didn't matter, they wouldn't ask).

<comment><USER7> They probably want more impressive things if you're older -- if you're 18, it's impressive to have created a single site and sold it for a few thousand dollars, and have that be your biggest achievement. If you're 40, it's less so.

</comment></comment><comment><USER8> "There's always a first"

\-- From the ancient and archaic TV show _Kung Fu_ that I used to watch with my pet dinosaur and rotary phone.

PS: You did not state your age(s)/age range, at least not that I can find.</comment>


GeForce AIB partners design boards without running actual benchmarks - <AUTHOR> https://www.guru3d.com/articles-pages/geforce-rtx-3080-and-3090-what-we-know,1.html <comment><AUTHOR> > No benchmarks have leaked, how is that possible?</comment>


Licences could kill MPEG-4 (2002) - <AUTHOR> http://news.cnet.com/Real-Licenses-could-kill-MPEG-4/2100-1023_3-892219.html

<comment><AUTHOR> I thought this historical document was appropriate to recent news. Key quotes:

" _The licensing structure is putting the technology on a path to become irrelevant in the PC industry_ " -- RealMedia CEO

and

" _Apple immediately rejected the proposed licensing terms, leaving the future of its QuickTime multimedia technology in limbo._ "

The article it links to is interesting too,

 _Apple spurns proposed MPEG-4 licenses_ :

<http://news.cnet.com/2100-1023-835740.html>

Of course with the benefit of hindsight we can see how well MPEG-4 part 2 did in the web streaming market. I think it's fair to summarize it as "killed stone dead by VP6".</comment>


Hillary Clinton. Who will guard the guards? - <AUTHOR> http://www.adamtownsend.me/hillary-clinton-emails/ <comment><USER2> Here is a more credible analysis from a law professor, not a random armchair pundit: [http://mediamatters.org/blog/2016/03/21/law-professor- explai...](http://mediamatters.org/blog/2016/03/21/law-professor-explains-why- hillary-clinton-wont/209438)</comment>


Ask HN: Article where a Meetup.com guy was talking about taking it 100% paid? - <AUTHOR>

Can't seem to find it. Anyone have it bookmarked? Paying 5 awesome points. <comment><USER2> here you go(scroll down to "dear meetup commmunity"):

[http://web.archive.org/web/20080120191653/http://www.meetup....](http://web.archive.org/web/20080120191653/http://www.meetup.com/changes/)

looks like meetup has removed the page from their site, probably why you couldn't find it.

<comment><AUTHOR> Hey, thanks!

I was actually looking for a post where one of the founders discussed their metrics after taking their startup 100% paid. He was talking about their process and the amount of setback they experienced.

<comment><USER3> Right now I work at Meetup, so if you could give a little more detail about what was in the post, I could probably just e-mail Scott and ask him for it directly.

<comment><AUTHOR> Oh, wow, cool. So the post was talking about how they decided to change from free to paid. He was talking about how they had an initial sharp downard turn in meetups, but eventually recovered.

Thank you!

<comment><USER3> response i got:

"Hi Yuri, unfortunately I don't recall any specific post I've written about it. I've mentioned & talked about it openly, but no particular post. Sorry"

<comment><AUTHOR> Ah, no problem. Thank you!

</comment></comment></comment></comment></comment></comment><comment><USER4> It's not a secret, every meetup organizer has to pay to run a group. From [http://www.meetup.com/help/billinghelp/#Doesitcostmoneytosta...](http://www.meetup.com/help/billinghelp/#DoesitcostmoneytostartaMeetupGroup)

There are 3 price plans: * USD $12 a month for 6 months (a single $72 charge) * USD $15 a month for 3 months (a single $45 charge) * USD $19 per month

Each plan has a 30-day money back guarantee. Organizers can run up to 3 Meetup Groups with their subscription.

For more information on fees, check out: <http://orc.meetup.com/archives/2006/02/the_lowdown_on_1.html>

</comment><comment><USER5> Is this what you were looking for?

[http://www.intuitive.com/blog/change_your_business_model_and...](http://www.intuitive.com/blog/change_your_business_model_and_kill_your_business_meetupcom.html)

This post offers some excellent advice.</comment>


You Are Not Seth Godin - <AUTHOR> http://www.twistimage.com/blog/archives/you-are-not-seth-godin/

<comment><USER2> >So, can every brand be Seth Godin?

>The answer is "maybe."

The example of Cory Doctorow building an audience (and hence a market) for his books by giving them away seems to support this optimism. What hasn't changed and likely won't change is that you still need to be _good at what you do_.

<comment><AUTHOR> True... very very true.</comment></comment>


Way to delay container startup to support dependant services – docker/compose - <AUTHOR> https://github.com/docker/compose/issues/374#issuecomment-169388370 <comment><USER2> So we're reinventing init/systemd with giant pseudo-binaries in the form of containers, because this time we'll get it right.</comment>


For Twitter, Sharing Data with Google Would Be Suicide - <AUTHOR> http://www.techcrunch.com/2009/08/22/for-twitter-sharing-data-with-google-would-be-suicide/

<comment><USER2> This comment from the article raises a very good point...

Go Twitter?

 _Twitter is the first company in years that has the potential to disrupt Google in their own game - Search.

No. They are not going to be the new general query search engine, but for certain queries they could be much better. For example, a couple of weeks ago I thought of going diving near Cancun. But I was afraid of the weather and the Hurricans in the area. All I needed to do is type "Cancun diving" in Twitter search and in seconds I got real time twitts of people who are actually there, talking about the dives they did just a hour ago.

And of course the obvious ad model is to now show me ads and deals for diving shops in Cancun.

This is the real promise of the real time search._

</comment><comment><USER2> Goog is much better than Twitter at serving relevant content to me. Are they so far ahead of the game that no one else can join? The #diabetes hash at Twitter has a lot of not-so-relevant material to weed through. The same search at Goog gets some pretty relevant material in front of me. If Twitter does make some search changes, won't users abuse the ability to capture the search queries? Great article though and I agree with the writer, it is going to be a great show to watch.</comment>


How to build your own private smart home with a RPi and Mozilla's Things Gateway - <AUTHOR> https://hacks.mozilla.org/2018/02/how-to-build-your-own-private-smart-home-with-a-raspberry-pi-and-mozillas-things-gateway/ <comment><USER2> Kudos to Mozilla, that's very nice work!</comment>


Google is rolling out or testing an update to the google interface. - <AUTHOR> http://pixelscraper.posterous.com/google-is-rolling-out-or-testing-an-update-to-0

<comment><USER2> That has actually been around for a couple of weeks at least.

I have noticed computers "getting" this new interface at random, but I still don't know when it's updated.

Still waiting for my turn, though.

<comment><USER3> About 5 or 6 weeks for me.

</comment></comment><comment><USER4> This just took effect for me and I hate it. Is there a way to opt out? I haven't been able to find one.

</comment><comment><USER5> Google is making good-looking stuff lately. The YouTube update, Chrome, and now this.

</comment><comment><USER6> I've had this since the beginning of the year in Chrome/Win7, a few months Firefox/Ubuntu and yet I don't have it in my main browser Chromium/Ubuntu.

Oh well, certainly not new though.</comment>


Show HN: Pueue: A daemonized Unix command line queue utility - <AUTHOR> https://github.com/nukesor/pueue <comment><USER2> very interesting, can I schedule tasks to run daily, hourly, weekly, etc. like cron.</comment>


The Groupon Model - <AUTHOR>

There is all this hype about Groupon and social buying. Why aren't advertising platforms doing this instead of buying platforms that do this?<p>Currently, the advertising platforms such as google adwords, facebook advertising, adbrite, buysellads.com, etc are all based on models that support "the highest paid advertiser will have the best placement." I know when I search, I want the best deals to show up - not who paid the most to give me the potentially worst deal for me. Opinions? <comment><USER2> Groupon takes an old model - "one day sale only" or "first 1000 people to sign up get a free t-shirt" - and makes it work in the social space.

Groupon is promotions, not advertising. Trying to compare it to Adsense will be extremely difficult.

</comment><comment><USER3> AdSense, to my knowledge, doesn't only optimize for maximum CPC but rather for max earnout for Google, a large part of which is the likelihood of you clicking the ad. This is a fair determination of the quality of the "deal"/ad, I suppose.

<comment><USER4> In my experience modern ad systems use, among other things, CPC x CTR. Using CPR x CTR is good for all stakeholders: 1\. Advertiser value - the better/well targeted the ad, the lower the cost 2\. Publisher value - higher CTR means more clicks, means more $$$. 3\. And most importantly, user value - higher CTR is generally a good indicator of better targeted ads

<comment><AUTHOR> Really good points. Thanks for the feedback. You still have to layout money before you make any, hence the reason why the groupon model is so enticing from an advertiser's perspective.

</comment></comment></comment><comment><USER5> Adwords on Google considers CTR as well as Quality Score to determine which ad will display, not the CPC that you're willing to bid.</comment>


How UMAP Works - <AUTHOR> https://towardsdatascience.com/how-exactly-umap-works-13e3040e1668 <comment><USER2> Nice article.

We recently used t-SNE and UMAP in the field of radiation damage, for visualising the damage shapes (point defect clusters of different shapes). The results were interesting in many ways.

We found that the general layout of classes of shapes is more or less same in UMAP or t-SNE, so the global & local relationship argument didn't really work for our data. Since, the data was around 1000 points of around 50 dimensional histograms, efficiency was also not a big distinction. For us, real advantage of UMAP came out to be its amenability to work with HDBSCAN and embedding new test data. We are excited to use it on further categorising cascade and sub- cascade shapes (bigger damage areas).

To check results see the following:

\- [https://haptork.github.io/csaransh/presentation/index.html#/...](https://haptork.github.io/csaransh/presentation/index.html#/8/1) : select the t-SNE or UMAP on left pane.

\- [https://haptork.github.io/csaransh/](https://haptork.github.io/csaransh/) : Go to last pane "Cluster Classes", click on a point to see the shape on right. Select between t-SNE or UMAP on the left pane. (might take time to load)

\- [https://arxiv.org/abs/1811.10923](https://arxiv.org/abs/1811.10923) : arXiv paper

\- [https://github.com/haptork/csaransh](https://github.com/haptork/csaransh) : GitHub repo

Ideas and suggestions are welcome.

</comment><comment><USER3> UMAP is awesome, and we usually recommend it to people who are struggling with tSNE performance issues. If you have access to a GPU, it's worth checking out cuML's UMAP implementation ([https://rapidsai.github.io/projects/cuml/en/0.10.0/api.html#...](https://rapidsai.github.io/projects/cuml/en/0.10.0/api.html#cuml.UMAP)), which is closely based on McInnes' original python code but is much much faster.

</comment><comment><USER4> How do you people who work with high-dimensional data outside of biology feel about t-SNE and/or UMAP?

Some of the points against t-SNE feel like comments that only non-computer scientists would make (e.g., t-SNE must be run on a cluster/needs a lot of RAM - despite the fact that rather few genetic datasets can be analyzed on the commodity laptops most common among biologists).

<comment><USER5> UMAP is basically one of the most innovative things I've ever seen. It's highly used in NLP with extremely good results

<comment><USER6> Example? Anything besides visualizing embedding spaces?

<comment><USER5> Any type of clustering

</comment></comment></comment></comment><comment><USER7> Very interesting read. I interpret this in the way that clustering (eg HDBSCAN) on UMAP-projected data makes some sense at least (contrary to tSNE), are there any differing opinions on this? Interesting related discussions: [https://stats.stackexchange.com/questions/263539/clustering-...](https://stats.stackexchange.com/questions/263539/clustering- on-the-output-of-t-sne)

<comment><USER8> Here's a pretty comprehensive answer on the topic from the original UMAP author: [https://github.com/lmcinnes/umap/issues/25](https://github.com/lmcinnes/umap/issues/25)

Clustering the output of UMAP is also given a nice tutorial in the docs: [https://umap-learn.readthedocs.io/en/latest/clustering.html](https://umap- learn.readthedocs.io/en/latest/clustering.html)

Basically, the answer is yes you can do this, but verify and analyze the output to ensure it makes sense (e.g. coloring points by known features/labels). For example, if you have a small number of points in the dataset (<1000), UMAP tends to display a dense cluster that is quite separated from the remaining data. However, this apparent cluster is spurious and contains noisy data points that UMAP couldn't "figure out what to do with" (they are similar in their dissimilarity to the other data).

</comment></comment><comment><USER9> Mediumwalled - i can't read this without signing in to something. Does anyone happen to know if there are cookies i can clear to work around this?

<comment><USER10> Outline is another great option - [https://outline.com/5MNPHn](https://outline.com/5MNPHn)</comment></comment>


Taking Issue with Paul Graham's Premises - <AUTHOR> https://glyph.twistedmatrix.com/2016/01/premises.html <comment><USER2> The author disingenuously wants you to believe that he's never heard of Moore's law.

<comment><USER3> Hm, can you explain how you see Moore's Law as relevant? It talks about the number of transistors on a chip, or at least most generally about the technical performance of a computer system; it does not address the actual contribution to the economy / to productivity / to society by transistors.

In fact, by the markets-are-generally-good-at-things hypothesis, and the generalization of Moore's Law that computing power _that can be obtained at equal price_ is growing exponentially, we have a good reason to believe that the exponential growth of technical performance is not contributing at all to productivity.

An uncharitable interpretation would be that most of the gains in technical progress have been lost to rent-seeking by the developers of ever-more- complicated frameworks and operating systems and UIs; while the ability to be productive on Google Docs today is higher than the ability to be productive on Office 95, it does not seem to be 2^(20 years/18 months) = 10,000 times higher. But nobody would put up with Office 95 today, for entirely artificial reasons.

<comment><USER2> >can you explain how you see Moore's Law as relevant?

The author explicitly asks: "In what sense does technology grow "exponentially"?" If the author wants to claim that the results of Moore's law hasn't trickled down to the common man, then he should do that. Pretending to not know about Moore's law just fails for me as a rhetorical device. The wheat example seems weak as well (not to say that there aren't many other weak point in the article). To make it stronger, he should create a plot of the number of human hours involved in harvesting a bushel of wheat vs. the calendar year, for say the last 2,000 years.

>In fact, by the markets-are-generally-good-at-things hypothesis, and the generalization of Moore's Law that computing power that can be obtained at equal price is growing exponentially, we have a good reason to believe that the exponential growth of technical performance is not contributing at all to productivity.

On a totally unrelated note, proponents of "Basic Income" seem to also be relying on ever increasing technology productivity to replace human jobs, paying their dividends to all. I wonder how those ideas square with each other, and how many of basic income advocates hold a technology- doesn't-produce-productivity (I'm not saying you or the original author are proponents of basic income guarantees).

<comment><USER3> But the number of bushels of wheat that the world needs harvested has been approximately constant per person for the last 2,000 years. If it took many humans' work days to harvest enough wheat for a community, and now it takes very few work days for the same size community, that's progress. But cutting it down past about one person-day isn't particularly more progress. Society is not particularly better for having one person per nation oversee the wheatbots instead of one person per city, in the way that it is better for having one person per city oversee the wheatbots instead of half the city be laborers.

That is the author's claim: whether or not the technical capabilities improve exponentially, the actual value to society quickly tapers off. The fact that the author is claiming that seems obvious enough to me from reading the article, and from reading pg's original essay, which is entirely about the market value of technology (not about technology itself).</comment></comment></comment></comment>


Show HN: A large-format, easy to navigate NYTimes RSS reader for iPad - <AUTHOR> https://github.com/cloudwalking/ZimZam

<comment><USER2> very cool. It'd be even cooler if you had a settings page to select which NYTimes feeds you wanted.</comment>


HoloKit – Google Cardboard for augmented reality - <AUTHOR> https://holokit.io/ <comment><USER2> cool but that design... fire the torpedoes!

edit: also that approach is faster than overlaying something on top of camera playback right? I mean obviously</comment>