Show HN: DropKick, a jQuery plugin for beautiful dropdowns - <AUTHOR>

As a weekend project I created a jQuery plugin that makes it easy to create beautiful dropdown menus with keyboard navigation. You can easily create your own themes and it works seamlessly with your existing forms.Please take a look at http://jamielottering.github.com/DropKick/ <comment><USER2> I've been meaning to implement this one for some time: [http://tutorialzine.com/2011/02/converting-jquery-code- plugi...](http://tutorialzine.com/2011/02/converting-jquery-code-plugin/)

It also allows images and degrades to pure select elements if necessary.

It doesn't allow for keyboard navigation (which is nice) but are there other benefits of DropKick that I'm overlooking in my quick glance?

The reason I haven't updated my select elements to these is because there are several cases on my site that a select will appear or disappear when the user engages with other parts of the site and the above code doesn't check for the visible state of the parent element. Any chance that's in your pipeline? I think it would make it more usable for modern sites (But maybe I'm the only one who frequently hides/shows select elements?).

Other than that, I like this. Thanks for putting it out there.

<comment><AUTHOR> Thanks for the feedback!

My goal with DropKick was to create a simple, lightweight select replacement that made designing awesome looking forms easier. I mostly want to keep it simple and light, but I like your idea. I'm currently hoping to add more interaction with DropKick such as changing the open/close animation or getting notified when the template renders.

</comment></comment><comment><USER3> I really like these, the only problem I've found is that in IE9 the gloss themes don't work. The dropdown appears but is empty. (I can get you a screen shot if you like)

Works well in every other browser/version I tried though.

<comment><AUTHOR> I've heard a couple reports about issues in IE9, I've been trying to install it on my windows machine but I've been having trouble. I'll keep trying and get it fixed for IE9

</comment></comment><comment><USER4> I really like the style. One thing to note: Whenever I encounter a select your state dropdown, I select it and type the first few letters of my state. Please consider implementing this functionality. Awesome work otherwise.

</comment><comment><USER5> Clickable: <http://jamielottering.github.com/DropKick/>

<comment><AUTHOR> Thank you</comment></comment>


What is the appeal of dynamically-typed languages? - <AUTHOR> https://gist.github.com/non/ec48b0a7343db8291b92 <comment><USER2> There are some good points here, but this essay falls into the same trap that so many let's-compare-type-systems discussions hit: assuming that _static typing_ means Java-style static typing.

Yes, the mostly-manifest, nominal-oriented type systems of PLs like Java and C++ can be wearying, and something like Python feels like a breath of fresh air in comparison. However, a more inferred/structural approach _is_ possible in a statically typed PL, as Haskell demonstrates so well.

Like Python, Haskell does not require you do "assert that x is a Collator" before doing some collation. It tends not to lead to complex hierarchies. And its standard containers are versatile and well supported.

The point here is that most of the issues discussed are not really issues with static vs. dynamic typing. They have rather more to do with manifest/nominal vs. inferred/structural typing, along with how much attention the PL designers gave to minimizing overhead & boilerplate.

The essay I really want to read is "Why I Prefer Python to Haskell" \-- particularly if it is written by someone who actually _gets_ Haskell.

<comment><USER3> Haskell provides functions like zip, zip2 and zip3 where an ordinary language just gives you a single zip that works with any number of arguments.

That's the kind of thing you do in C. For instance Unix: dup, dup2. (Linux adds dup3!)

That doesn't pass the "smell test", relative to all the claims about how Haskell and its ilk are the most amazing thing since sliced bread.

<comment><USER4> Polyvariadic functions are possible in Haskell:

[http://okmij.org/ftp/Haskell/polyvariadic.html#polyvar- fn](http://okmij.org/ftp/Haskell/polyvariadic.html#polyvar-fn)

<comment><USER3> While this establishes existence, it seems way too cumbersome for production use. Both creating a variadic function _and_ calling it require awkward boiler-plate, like the verbose and cryptic signature on use_build.

</comment></comment></comment></comment><comment><USER5> Got to this:

"In an interesting way, it keeps you from going all-in on object-oriented programming. You only want to create a class when a casual API user will understand how it works and what they would use it for. "

Completely disagree. Python doesn't discourage OO at all. I think the author has a particular programming style with Python that does not line up with the way many people I know use it, and this may give the wrong impressions. Yes, you can just pass around tuples, but ... don't do this :) It has quite workable classes.

So, answering the question? What's the advantage? Dynamic language does require, to a degree, a small amount more tests. However, type errors are also a class of error that is very very infrequently encountered as to a problem.

I'd say that duck typing principly allowers easier mock interfaces and ability to more easily write generic-type functions, and for unrelated reasons, such languages have a very quick code-test loop. But their efficiency in this isn't so much to do with typing. It's mostly the speed of this loop, stemming from a lack of compilation, that helps. Those are not really related, but that's why people like dynamic languages.

They have also been historically more expressive, and saved typing things, for when type errors aren't really common (for me, they aren't), always specifying types doesn't always help. But to be honest, I don't mind it and it's nice to have as documentation most of the time.

I do mind compilation cycles.

The article also seems to err in that it assumes there can't be debuggers available for typed languages, where it says "you can't see inside the process".

The argument that people like dynamic systems because they build programs out of trial and error seems erroneous in all. I build my programs out of tests. This can still happen just the same and has nothing to do with a type system.

<comment><USER6> _" However, type errors are also a class of error that is very very infrequently encountered as to a problem."_

As someone working every day in Python, this seems mind-bogglingly divorced from reality.

I don't know if you mean something far more restricted by "type error" but most of the errors I encounter - in my code, the code of my team, and the code of those on other teams, across several projects - are errors that would have been caught by the type checker in Haskell had I been writing similar code. Many of them would have been caught by the type checker in C.

<comment><USER5> Hmm, that's curious, though I don't think it's ever a good idea to tell someone they are divorced by reality :)

I think some types of developers are more likely to make type error mistakes, and it's likely I make _other_ mistakes, sure. I've done a wide about of massively-open source projects, and it doesn't really come up. The times I pass the wrong object type simply doesn't happen.

Do you use keyword arguments? These help a TON with argument order, and may be why you are having that problem.

<comment><USER7> When I write code and tests in JavaScript, typically the tests turn up a few typos and "brain-os" in the code (that don't keep it from parsing). Many or most of these would be caught by the type-checker in statically-typed language.

Maybe you don't "see" type errors because you consider them to be failures of test coverage, or you say, "That's not a bug, it's more of a typo?" Or you don't work on a shared codebase?

<comment><USER5> Neither. I don't make them often, and I do work in quite shared codebases - one of them had over 1000 contributors. I won't pretend I'm a better developer, I surely make other classes of mistakes, usually it's "I didn't consider the user scenario where this file didn't exist or the error path when this file has invalid contents should really raise a better exception than a generic stacktrace".

<comment><USER6> A static type checker could be of some help in both of those cases, if you use it well.</comment></comment></comment></comment></comment></comment>


De-anonymizing programmers from executable binaries - <AUTHOR> https://blog.acolyer.org/2018/03/16/when-coding-style-survives-compilation-de-anonymizing-programmers-from-executable-binaries/ <comment><USER2> I did a lot of work on authorship attribution for natural language.

I found it was easy to get mind-blowing results on a single dataset - e.g. 99% accuracy for working out who wrote which emails in the Enron [0] dataset.

The moment the test set was even slightly cross-genre, results became bad.

So this is great in theory, but I would love to see a test set from the same authors outside the context of the Google Code Jam. I'd be surprised if the results were anything like as good.

There are very few real-world cases where you have a large amount of same- genre data for the questioned author. (No one writes a thousand suicide notes / ransom demands / scams)

[0] A large email database often used for authorship tasks [https://www.cs.cmu.edu/~enron/](https://www.cs.cmu.edu/~enron/)

<comment><USER3> Great point. A system needs to be forward tested not simply back tested on a known set of data.

Incorrect back testing is absolutely standard with stock/bond/forex/etc trading. There are a million hustlers who sell their back-tested systems. In essence, without forward testing all you have is an untested hypothesis.

</comment></comment><comment><USER4> I would be very interested to know how the accuracy changes if you remove symbols and strings from the analysis.

Symbols and strings are free-form text that would seem to leave a lot more of a stylistic fingerprint. If you could get this level of accuracy from machine code alone, I would be very surprised.

The article says that stripping symbols reduced accuracy by 24%. This is a far greater drop than from optimizing the binary. It leads me to believe that a large part of the success in classifying is coming from symbols and strings.

</comment><comment><USER5> This isn't a surprising result if you know what competition programming code looks like.

Everyone has their own distinctive personal library/template/boilerplate that they are pasting for every problem since includes, typedefs, defines, library helpers, IO, etc are always the same.

You can see some examples here to see what I mean: [https://www.go- hero.net/jam/17/solutions](https://www.go-hero.net/jam/17/solutions)

</comment><comment><USER6> Very interesting. The accuracy achieved is quite impressive -- I think it would be lower when the technique would be applied in practice, since the assumptions that are made are quite strong. For looser assumptions (no disclosure about the compiler/optimization level, highest optimization level enabled, larger pool size), the technique is less accurate.

In practice, it might be interesting to give a fuzzier output - the esimated probability that an individual wrote the code for a certain binary. This would help when two programmers (say, Alice and Bob) write code that yields binaries with similar properties. In the current system, either Alice or Bob is picked -- there is no way to express that it might be either of them.

</comment><comment><USER7> How much is there code available written by Hal Finney?

<comment><USER7> Although we have the actual source code for Satoshi's Bitcoin implementation so not exactly relevant to the article

<comment><USER8> Uhh Satoshi is Nick Szabo...

<comment><USER9> Wei Dai's AMA makes me doubt that.

[http://lesswrong.com/lw/jgz/aalwa_ask_any_lesswronger_anythi...](http://lesswrong.com/lw/jgz/aalwa_ask_any_lesswronger_anything/ap3c)

Specifically this comment [http://lesswrong.com/lw/jgz/aalwa_ask_any_lesswronger_anythi...](http://lesswrong.com/lw/jgz/aalwa_ask_any_lesswronger_anything/ap3c#)

<comment><USER10> > No I don't think it's Szabo or anyone else whose name is known to me.

I have always thought the speculation about SN's identity suffered alarmingly from availability bias. Everyone wants to believe he's someone they know about. Someone who's extremely well-known for working on or writing about things extremely similar to Bitcoin. There are far more smart nobodies tinkering with things than there are top names working on those things.

Also suffers from a bias I'll call "Shakespeare didn't write Shakespeare bias." The idea is that a notable thing must have been written by a high- status and well-credentialed person, and could not have been done by a talented no-name.

<comment><USER11> > The idea is that a notable thing must have been written by a high-status and > well-credentialed person, and could not have been done by a talented no- > name.

I think your reasoning is interesting. Nevertheless consider that if we hunt for SN, it is very likely that it is at least a person who knows more than a little bit about various topics that were necessary to implement Bitcoin (e.g. finance, cryptographic hashed data structures, existing protocols for crypto cash, ...). I agree that it is quite possible that this could also be a talented no-name, but I think this property provides a strong criterion to check if someone claimed that some specific person (who is a talented non- name) they have in mind is SN.

Also one would have to provide an explanation why such a person is not more well-known. It can be that he/she has a difficult personality. It can also be that he/she lives in a country where such a person will have a lot less opportunities etc. But these constraint again limits the circle of talented no-names that could be SN.

TLDR: Your reasoning is interesting, but your hypothesis has strong consequences.

<comment><USER10> I don't believe lack of notability needs any explanation at all. It's the default. I have plenty of [anecdotal] evidence that exceptional skill is one of many factors that might contribute to notability. Other factors include networking or self-promotion, timing, and chance. Being a lurker type myself, I've encountered many fellow lurkers in forums over the last 20 years, who demonstrated astounding expertise, but are afaik almost completely unknown in my industry. I can think of many more people who actually are at the top of the industry, but are relatively unknown simply because they do not give talks, blog, or write books. In case it wasn't obvious, my personal _hypothesis_ is that SN was simply a very skilled lurker in the cypherpunk scene. I doubt he was Finney, Dai, or Szabo, but I suspect he was someone who, like myself, was well aware of them and hung out in the same forums and lists.

</comment></comment></comment></comment></comment></comment></comment><comment><USER12> Back in the late 80s/early 90s it was quite possible to tell the author looking at the disassembled portion of a virus. (when all viruses were virtually written in assembly)

I don't think much has changed.

<comment><USER13> Came here to say the same thing. Back in the early 90's one of my friends spent time obsessively studying the personal nuance of code attributed to The Dark Avenger. Even in code that had obviously been optimized bits of personal nuance leak through. It seems very intuitive that compiled languages, being more expressive, would leak more personal nuance.

<comment><USER12> Well that was easy, given the signature of triple 6 :D (although that part dropped due to space considerations)

</comment></comment></comment><comment><USER13> I immediately thought of the anecdote about World War II British SIGINT operators being able to identify individual German telegraphers by way of their distinctive style of Morse keying.

[http://listserv.linguistlist.org/pipermail/ads-l/2005-April/...](http://listserv.linguistlist.org/pipermail/ads-l/2005-April/048637.html)

[https://web.archive.org/web/20100820000534/https://www.wnyc....](https://web.archive.org/web/20100820000534/https://www.wnyc.org/books/42607) (Search for 'fist')

</comment><comment><USER14> Can it help forensic determine if it's the same attackers behind different incidents?

<comment><USER15> Perhaps in the past. In the future, attackers will just modify their code until this test returns a different predicted author.

<comment><USER16> anyway, I don't think this would ever be accepted as evidence in trial. it could be an indicator/lead for investigations, but I don't think it would be a big concern for attackers?

</comment></comment></comment><comment><USER17> The conclusion that more experienced developers develop their own style is an important one. It shows that good programming is not about adopting convention.

<comment><USER18> There's a principle in art about "knowing the rules so you know when and how to break them". You can't pass off bad art as good with the excuse of "it's just my style, man". Well, maybe you can in the elite galleries, but not in the workaday world of commercial art (e.g., for advertisements, video games, comics, cartoons, etc.) You have to learn the fundamentals and work within those bounds, then once you "git gud", only then develop a personal style. I suspect the same is true of programming.

</comment></comment><comment><USER19> After linters, it seems now we've to run our code through code anonymizer too.</comment>


JavaScript is Web Assembly Language and that's OK. - <AUTHOR> http://www.hanselman.com/blog/JavaScriptIsWebAssemblyLanguageAndThatsOK.aspx

<comment><USER2> No, it's not, and it's certainly not OK. Javascript is a quirky interpreted scripting language created for scripting minor workflow events. It's an afterthought by Netscape, duct-taped to a bundle of silly hacks, wrapped up in some interesting attempts to standardise, with a few more vendor-specific hacks crowbarred in there for good measure. asm.js is one more hack on top of the mess, and while it's technically interesting, and probably very useful (much like the rest of javascript), we shouldn't be building these monstrous feats of engineering on top of such shaky foundations.

> there's only one language that works everywhere without installation or > trouble and that's JavaScript.

This is true. But we've arrived at this situation virtually by chance, and it's a huge mess and we shouldn't be readily accepting it. We need a real bytecode for the web, we need it to be standardised and we need to push for browsers to support it. NaCl seems to be the furthest down the road to this objective so far.

<comment><USER3> > We need a real bytecode for the web, we need it to be standardised and we > need to push for browsers to support it.

We had one. It was called Java. Actually, we still have it, but it just has such a bad reputation now; users don't trust it because of "security" and developers don't trust it because of "public static cruft()" and "Oracle".

But it is still quite capable. Did anyone else first play minecraft in a web applet? It worked incredibly well for me. So I argue that we do have a viable bytecode, we're just ignoring it.

<comment><USER4> The experience sucks beyond compare, always has, and blaming the user isn't going to solve that.

You have to download a separate plugin with stupid ads in it. If your version is wrong, it won't work or it won't work right. A number of things won't work unless you use the one from Oracle. If you are lucky, a little tray reminder obtrusively harasses you every few weeks to update to a new version. If you don't, you have to worry about unpatched vulnerabilities. Now you come across a page with an applet in it. This applet stuck inside a little rectangle on the page takes a few seconds to kick off at all. Most of the time it looks terrible once it's up. It isn't at all uncommon that it crashes. Many people have experienced this bringing down the browser or even hanging the computer, which is especially awesome when you didn't even ask for the thing to run.

This isn't a matter of the users being stupid and not knowing what's good. This isn't good. It has never been good.

</comment></comment></comment><comment><USER5> One of the endearing qualities of web design and development was how the source was open for everyone (HTML, CSS and JS). Developers could read the code, understand and remix each other's work. This helped in its rapid growth from a design platform to an application platform.

Enter asm.js, where the source code is as readable as a compiler's assembly output. Once again we are back to code that is hard to hack and improve. Sort of similar to the days of Flash except that entire applications are being built on this platform.

It might be a great end user experience, but it is not the best way forward for web development.

<comment><USER6> > Enter asm.js, where the source code is as readable as a compiler's assembly > output.

What do you mean? Isn't it roughly as readable as C?

<comment><USER7> No, it's roughly as readable as decompiled executable, without even a symbol table to provide semi-readable names. John Resig has a somewhat reformatted example a couple of pages into this: <http://ejohn.org/blog/asmjs-javascript- compile-target/>

<comment><USER6> I'm not following you. Are you referring to the minimized code that has been beautified? Of course it is not going to be particularly legible. Same for any minified code, asm.js or not.

From the link you gave, the DiagModule function is asm.js, and every bit as readable as C.

<comment><USER7> Sorry, I was unclear. In this context, which if you follow back up to arocks' post is in the context of using "View Source" to learn how things are done, I'm referring to the sort of asm.js that comes out as a result of compiler output, not stuff written by hand. The Gist is what I was pointing at. There is no way you're going to read that and learn how, say, the Unreal Engine port does something.

I think people may think I'm trying to be faintly critical, but I'm not. It's just the nature of the beast.

<comment><USER6> > I'm referring to the sort of asm.js that comes out as a result of compiler > output

That Gist - what is visible from "View Source" after beautification - _is not compiled asm.js code_. It is not the result of any compilation. It is the result of minification. Most minified code is as illegible as that.

<comment><USER7> Yes, it is. (Perhaps not entirely, but it's generally what you're going to find in the wild.) Read under the Gist for the bullet points. It may be minified, but that's not what makes it impossible to understand.

Hand-written asm.js code is not going to be the norm, for the forseeable future, for a variety of reasons. The rules for the grammar are difficult and tedious to manually write. The fact that everything runs in a massive array, so you've got a lot of memory management to write, is going to be a problem. The existence of numbers like 1384465 and 4980736 is what makes that particularly hard to read. Most asm.js code on the web is going to be incomprehensible; the examples you can read are the exceptions, for didactic purposes, not the rule.

<comment><USER6> > Yes, it is [compiled]. (Perhaps not entirely...

Wow. No, it absolutely is not. I have no idea what you could possibly mean by "not entirely" compiled.

>The rules for the grammar are difficult and tedious to manually write.

There's nothing difficult about the syntax. It's a subset of javascript.

> The fact that everything runs in a massive array, so you've got a lot of > memory management to write, is going to be a problem.

No more difficult than managing memory in C.

> The existence of numbers like 1384465 and 4980736 is what makes that > particularly hard to read.

The lack of _meaning_ for those numbers is what makes it hard to read. It wouldn't matter if 1384465 were 2 or "a". It's been minified, so the meaning has been stripped away. I agree that it is hard to read, but it's not a result of using asm.js, it's a result of minification and auto-generating code. There's nothing inherently illegible about asm.js.

> Most asm.js code on the web is going to be incomprehensible; the examples > you can read are the exceptions, for didactic purposes, not the rule.

Sure, just like most javascript on the web is incomprehensible, by virtue of being minified or auto-generated.

</comment></comment></comment></comment></comment></comment></comment></comment><comment><USER8> I don't understand why people say such silly feats of pseudo-"engineering" are somehow "OK" and acceptable. How have we arrived to this situation?

I get that 1) agreeing upon a more sane bytecode-based language for the web 2) implementing it on all major browsers 3) changing the tooling and workflow(no more a .js file, save and open in browser but a compiled file instead) would perhaps be not worth the benefit(more sane target, better support for common programming constructs without performance, safety or determinism issues and so on).

Simply, people don't give a fuck, web works "well enough" and iterative engineering solves the major problems. These just are things we have to deal with, something we can't change, which I find pitiful but understandable, but most definitely _not_ "OK" or acceptable.

<comment><USER9> > I don't understand why people say such silly feats of pseudo-"engineering" > are somehow "OK" and acceptable.

Network effect and worse is better.

Any solution that cannot be introduced gradually with backwards- and forwards- compatibility is very unlikely to gain traction on the web. You'll always get a vendor that doesn't like some tech or has multi-year-long development/distribution/upgrade process. Tools can be even slower to upgrade and you'll also need to educate developers and get them out of their comfort zones.

It's not that people don't give a fuck. It's not pseudo-"engineering". It's the best you can get within constrains that are both technical and social.

</comment></comment><comment><USER10> It would be OK if Javascript was a better language. It is terrible, but it works. Most importantly, there is no alternative. That's why we use it.

<comment><USER11> That doesn't account for node's popularity. I like Javascript. That's why I use it.

<comment><USER12> I'm not an arbiter of what makes things popular, but from what I can see, Node's popularity has more to do with the fact that front end guys no longer have to learn a new language to work on the back end.

</comment></comment></comment><comment><USER13> JavaScript is a kludge. It's a bag on the side of a bag. The amazing thing is that it works well enough to be useful.

<comment><USER14> JavaScript is a dynamic language with C-syntax, prototype-inheritance and lambdas. Embedded into every browser on the planet. Whats not to like?

<comment><USER15> Also, no integers. Who needs integers anyway?

<comment><USER14> Ok, thats true. And some of the built-in functions are crazy - parseInt("09") anyone? - but the basic workings of the language seem ok to me.

<comment><USER8> The problem is that when the base language has such limitatios and funky semantics, how should languages which target that be able to deal with that in 1) standard 2) predictable 3) efficient way?

This is the reason CPU instruction set architectures are so simplistic and "low level" and don't really do things for you -- because if they did, targetting such a CPU would be a _major_ pain with all inefficiencies due to workarounds due to funky and incompatible features.

</comment></comment></comment></comment></comment><comment><USER16> I bet that in less than 10 years we are running a standard VM in the browser instead of Javascript.

BTW, it would be interesting to add real $$$ bets in HN. In this way users can play with real money, not only with argumentation.

<comment><USER17> <http://longbets.org/>

<comment><USER16> Yes, I would like to have one integrated in HN :-)

<comment><USER17> I wouldn't bet against you on this!

</comment></comment></comment></comment><comment><USER18> Thanks to JavaScript we rediscovered functional programming, because we realized that the inheritance model Java polluted everywhere just stinks.

</comment><comment><USER19> What bothers me about asm.js and Emscripten is that, if used on a large scale, they'll perpetuate the C memory model, that is, a single flat heap of arbitrary size in which things are referenced via fixed pointers. Perhaps this memory model is necessary for small pieces of high-performance code, but I wouldn't want us to keep using it as the primary memory model for new applications, especially when at least some of the current JS engines have advanced copying/compacting garbage collectors.

I would love to have a memory-safe language that compiles to efficient JavaScript with no intractable semantic or runtime mismatches between the JS and the source language or its libraries (e.g. no preemptive threads with shared memory) and takes full advantage of the JS engine's garbage collection, but can also be compiled ahead-of-time to fairly efficient native code for environments where JIT compilation isn't an option (e.g. iOS apps). I suspect that a language like this would need static typing. To gain traction, such a language would need to stick to fairly mainstream concepts (e.g. not purely functional). Perhaps this language could be a subset of JS itself. The trouble with Java and C# is that their standard libraries and most third-party libraries assume multiple threads and blocking APIs; perhaps the compiler to JS could transform the code into continuation passing style.

</comment><comment><USER20> Isn't it more like, uh, Java for the web, except without a bytecode? This analogy is just weird.

<comment><USER21> Java was always an external plugin to the web (like Flash), while JavaScript sits more comfortable in the same shelf alongside HTML and CSS.

<comment><USER20> The web is an external plugin to the computer. JavaScript is its programming language.

</comment></comment></comment><comment><USER22> JavaScript is most emphatically _not_ the assembly language of the web. It is instead the _lingua franca_ of the web. I actually think this is what people intend to convey when they say this sort of nonsense.

</comment><comment><USER23> I had a silly idea. Why not make LLVM a part of browsers? I heard it was a really performant albeit hard to write languages in. It seems to not have the stigma attached to JVM, especially association with oracle.

<comment><USER19> This is what PNaCl (Portable Native Client) is trying to do. I'm skeptical though; PNaCl is still experimental in Chromium 29 (the current development version), and requires the browser to download extra files outside of the Chromium package itself, probably because LLVM is quite bulky. If we're going to run high-performance code with the C memory model in a browser, I think asm.js is the best way to do it.

</comment></comment><comment><USER24> I prefer to think of it as web COBOL.</comment>


Google-area housing plan slashed in Mountain View - <AUTHOR> http://www.mercurynews.com/2017/06/23/mountain-view-slashes-planned-google-area-housing/ <comment><AUTHOR> . . . and this would be why housing costs in Silicon Valley are so outrageous.

And those housing costs have spillover effects in Portland, Seattle, and elsewhere: [http://jakeseliger.com/2015/09/24/do-millennials-have-a- futu...](http://jakeseliger.com/2015/09/24/do-millennials-have-a-future-in- seattle-do-millennials-have-a-future-in-any-superstar-cities)

<comment><USER2> Did you read this _specific_ plan and note its specific location, trapped between 101 and the Bay with only two routes out, both of which are _already_ gridlocked during commute hours?</comment></comment>


Why I never finish my Haskell programs - <AUTHOR> https://blog.plover.com/2018/09/03/#what-goes-wrong <comment><USER2> I think many beginning Haskellers have this problem. To overcome it, my advice is to write Haskell code with the knowledge that you can re-write it more readily than you can re-write code in many other languages. Write the code that fits the immediate application, and rely on the type-checker to make it straightforward to refactor when the need arises.

I think that's what many experienced Haskellers would say is the language's best attribute for getting things done, that the type system makes it possible to refactor even a large program with the confidence that all the parts you replace will slot perfectly back into the original structure. Or that changing the core structure itself will result in a new structure that has all the right slots for all the various bits and pieces that need to slot into it. Having the confidence that you will be able to refactor painlessly, you should be less concerned with finding the perfect abstraction up front. Write code, make it work, then make it better.

And as others have mentioned, yes, the right abstraction and appropriate level of generality will become easier to recognize as you write more Haskell. Go with the first decent implementation you can come up with, and as you gain experience that first implementation will more and more often turn out to be a good one. In the meantime, run HLint and read more Haskell code, and you'll quickly pick up most of the generalizations that really make sense to use in typical applications. The more experienced you get, the more confident you should become that significant time spent generalizing code to no real purpose is pointless and tends to result in code that both reads worse and runs worse than what you started with.

<comment><USER3> In my case, I think it's because large programs always end up containing subproblems that can be better expressed in other paradigms than functional. And it becomes frustrating when I can't shoehorn them to the Haskell way of doing things.

My favorite languages are, for this reason, multi-paradigm: Common Lisp, Mozart/Oz, Scala and C++. It's a bit like building _La Sagrada Familia_ (and that's why it's depicted in the cover of CTM). If you want a superb solution, you end up using many styles like Gaudí did.

But I reckon the future will move towards more provably correct solutions, and we will be using things closer to e.g. Idris. Hopefully that's orthogonal with homoiconicity.

<comment><USER4> I agree with your sentiment, but I find the analogy to La Sagrada Familia funny, in that is has still not been finished, it's a black hole for money, and you can see, clearly, it's a hodge-podge of styles... All characteristics that might not be good for your software project.

<comment><USER5> which large software project has ever been 'completed'?

<comment><USER6> A lot of single-player (not online serviced) computer games could be regarded as 'completed': once they're out on the store shelves, it's pretty much done (although with the rise of Steam and continuous updates this is less of a case)

That's probably why many game programmers are more pragmatic in their programming practices: they have a concrete deadline to pursue, with a predictable subset of hardware for their program to run...

<comment><USER5> point taken, a lot of software in the pre internet era could be considered completed - on the other hand there's always still going to be issues, so you could also claim that these projects are just abandoned.

In general I think software is more like a house than an art piece - it keeps adapting as long as people use it.

</comment></comment></comment></comment></comment></comment><comment><USER7> I'm reminded of one of my favourite HN comments on Haskell:

'There's something very seductive about languages like Rust or Scala or Haskell or even C++. These languages whisper in our ears "you are brilliant and here's a blank canvas where you can design the most perfect abstraction the world has ever seen.'

[https://news.ycombinator.com/item?id=7962612](https://news.ycombinator.com/item?id=7962612)

Although it's not 100% applicable in this case (unless you argue that the cost is to your own time) - I think the sentiment is perfect.

<comment><USER8> I think Rich Hickey described it pretty well when he said (paraphrasing from [0]) that static languages present the programmer with neat little puzzles to solve that _feels_ like we're writing applications but we're just creating intricate types and abstractions. I think he has a point, but I certainly don't want to give up the benefits of static languages, like being able to catch all of my silly errors.

[0] [https://youtu.be/2V1FtfBDsLU?t=39m44s](https://youtu.be/2V1FtfBDsLU?t=39m44s)

<comment><USER9> His argument begs the question.

If you pre-suppose that describing types and finding appropriate abstractions aren't "writing applications", that is, they offer no value in the process, then spending time doing them is of course solving neat little puzzles to no benefit.

On the other hand, if you pre-suppose that types and abstractions offer some value to the process of writing an application, then solving those puzzles is adding value.

Calling types and abstractions a "neat little puzzle" is a diminution we could apply to other aspects of writing an application: implementing an algorithm to correctly process some data is a neat little puzzle presented by our test cases.

Rich Hickey would need to demonstrate the lack of value of types and abstractions for producing applications to make a solid argument here, and that I believe is a steep uphill battle, because Clojure would be a pretty terrible language if you took out the ISeq abstraction, and there's an awful lot of effort spent shifting the puzzle of "is this function being used right" from the type system game engine to the test harness game engine.

<comment><USER10> Time spent with a type system buys you compiler-checked proofs of some properties _. The important question is whether the time is worth the benefit.

One of many things that I love about the TypeScript type system is that it gives so much power to the author. It is the most expressive industrial type system I know of, but it also makes it easy for the programmer to say "I can't prove that this is true, just trust me that it is".

_ A nice side benefit is that this is also practice, so you can also gain skill. This is how I justify sometimes spending much more time with the type system than it would otherwise be worth when learning a new language or hacking on a personal project.

<comment><USER11> > One of many things that I love about the TypeScript type system is that it > gives so much power to the author. It is the most expressive industrial type > system I know of, but it also makes it easy for the programmer to say "I > can't prove that this is true, just trust me that it is".

I really wanted to like Typescript, but once you're thinking in HKT it's incredibly frustrating to have to manually translate a function into its flattened expansion (just like it's incredibly frustrating to use a type system without generics once you've used one that has generics). Every serious industrial language allows a programmer to say "I can't prove that this is true, just trust me that it is"; I suspect many people who struggle to start out in Haskell would do well to make a little more use of unsafeCoerce and unsafePerformIO (they would no doubt give themselves runtime errors, but sometimes the easiest way to understand why you had a type error is to run the code and see what the values are at runtime).

(I made a small hobby tool with ScalaJS and was amazed how easy it was, so I'll be advocating for that over Typescript).

</comment></comment></comment></comment></comment><comment><USER12> Coming from Prolog I'm loving Haskell, but I'm seeing a special kind of "worse is better" at work here: that projects using innovative and sophisticated languages have a high risk of running into obsessive "getting it right" and "holier than you" mentality resulting into them often getting never finished, and even if finished, having a high barrier of attracting contributors. It's unfair and embarassing, but shitty languages like JavaScript and PHP often allow you to be more utilitarian and churn out good enough code because you're not emotionally attached to them, and aren't under peer group pressure to express eg. algebraic properties in their purest form or some such.

<comment><USER13> I'll put a slightly different spin on this: At my current job the system I'm writing is in PHP (for reasons...). In its core it's all about domain modelling with some workflow sprinkled on top. Haskell would be a near perfect fit, but it can be done in PHP. However the code itself looks very Haskelly. I have a growing library of domain specific types that are composed into larger and larger tree shaped ADTs all the way to the top level entities. Validation is mapping/folding these ADT trees where nodes are (type, data) pairs that are mapped to their instantiation or its failure. The workflow bit is essentially a couple of FSMs with conditional transitions where the condition is usually the existence of some type that fulfils its constraint. Etc...

Reading it back it sounds analogous to the classic saying of one can write fortran in any language. In my opinion having experience with Haskell gives you a mindset first and foremost. When you bump into a problem where this mindset is a good fit you can use that knowledge with whatever tools are at hand.

</comment></comment><comment><USER14> I definitely find there's a strong relationship between language complexity and bikeshedding. When you have a big language like Haskell or Scala, it's easy to get distracted from solving the actual problem by trying to do it the most "proper" way possible. This is also how you end up with design astronautics in enterprise Java as well where people obsess over using every design pattern in the book instead of writing direct and concise code that's going to be maintainable.

Nowadays I have a strong preference for simple and focused languages that use a small number of patterns that can be applied to a wide range of problems. That goes a long way in avoiding the analysis paralysis problem.

<comment><USER15> I don't disagree in general but is Haskell a big language?

<comment><USER16> Haskell has a ridiculous number of obscure operators. Here's a list of "common surprising" operators in Haskell:

[https://haskell-lang.org/tutorial/operators](https://haskell- lang.org/tutorial/operators)

<comment><USER17> I don't think it makes sense to characterize Haskell as "big" on this basis, because 1) it is trivial to define an operator in Haskell, so there's bound to be a lot of them and 2) even the "standard" operators typically have a simple definition (e.g. [https://www.stackage.org/haddock/lts-12.9/base-188.8.131.52/src/...](https://www.stackage.org/haddock/lts-12.9/base-184.108.40.206/src/GHC- Base.html#%24)).

<comment> village-idiot On the whole, I consider user-defined infix operators to be a huge mistake. While the few common ones are great, the ability for every single library creator to add their own infix operator turns into a mess in the long run.

<comment><USER18> They fine inside a limited domain-specific scope, just don't go importing operators from many libs willy-nilly.

<comment> village-idiot It's very hard to convince people to keep them in that limited scope.

</comment></comment></comment></comment></comment></comment></comment><comment><USER19> There's a weird interpretation here that this post is the author expressing frustration with this process. I often have a similar experience and I wouldn't want it any other way! This process of repeatedly asking "what _is_ this?" just doesn't seem to come up in the same way in other languages. This gives me the ability to do some practice I wouldn't otherwise be able to do, one that often has tremendous transfer over to "real work", because I can start to see patterns and get a feel for what is really going on once I get rid of all the dull IO tedium.

If you want an analogy, consider this like studying jazz or something. Sure, you could just notice a II V I progression and call it done, but if you pick away at each individual note, you can find a whole lot more going on behinds the scenes.

Basically, I don't really consider what's happening in the blog post a bad thing. It just has a time and a place, and you need to be aware when it's the wrong time.

</comment><comment><USER20> I've seen this, and I've never had a Haskell gig. One of the best pieces of advice I ever got re: programming was, "don't write the abstraction until you've written three cases first". This is good advice in the intended way (you will write the abstraction better when you get to it), but even better because you probably often won't ever write three of the thing in question, in which case you shouldn't write the abstraction anyway.

<comment><USER21> > One of the best pieces of advice I ever got re: programming was, "don't > write the abstraction until you've written three cases first". This is good > advice in the intended way (you will write the abstraction better when you > get to it),

I don't think this is good advice in the context of Haskell. Haskell allows some abstractions that aren't just "black boxes" or glorified templates. It's of kind like elementary logic: the more models there are, the fewer proofs there are, and vice versa. Analogously, when you write a more abstract function, there are fewer ways you can manipulate it and thus it is in some sense simpler.

<comment> dan-robertson I half agree with you. I think the "abstraction" your parent is talking about would correspond to typeclasses rather than polymorphic functions. That is, I think that this would be a reasonable type for a function even if it is only called once:

      Eq a => a -> MyObj a -> Maybe Foo

Whereas I think the following would not be ok (probably even if you had a lot of instances)

      class HasFoo o where
        getFoo :: Eq a => a -> o -> Maybe Foo

      instance HasFoo MyObj where ...

I think the rule should be that one should write the most general code that minimises the entropy/size of the source code. That way one can prefer polymorphic functions (as they need less type-signature entropy and bytes, unless they have loads of constraints, in which case one should consider wrapping those constraints together), while still preferring not making crazy single-instance typeclasses.

</comment></comment></comment><comment><USER22> I think the main reason is that there is no _actual_ problem that OP needs to solve. If there was one, then he would get pragmatic and figure out one of the reasonable solutions to this and move on with his life.

Though it's true that Haskell is easy to put you into a mindset where you want to simplify and generalize the code as much as possible, leading to wasted time on overly general solutions. Which shouldn't be the case, because e.g. if you want to extend the solution from lists to traversables, Haskell gives you the confidence to safely refactor the method at a later time.

<comment><USER23> I lost confidence in Haskell's ability to let me write something one way and safely refactor it later, when I found out that you can't use a ton of the algorithmic functions in the standard library because they do things all wrong.

<comment><USER24> What?

Other than strings desperately needing to be purged from the library, what are you talking about?

Haskell has some really solid standard libraries, and it's extended library set has some of the most sophisticated algorithms packages in the world.

<comment><USER7> I'm not the commenter you're replying to, but I've often found the Haskell numeric classes (Num, Fractional, Integral etc) prickly. The _almost_ , but don't quite, map to (mathematical) algebraic structures.

<comment><USER25> Having use Haskell for math programming, I agree with this sentiment. Haskell's standard classes are in an uncanny valley of matching the mathametical structures.

If you want to do that sort of thing with Haskell, I would suggest switching to the numeric prelude [0]

[0] [https://wiki.haskell.org/Numeric_Prelude](https://wiki.haskell.org/Numeric_Prelude)

</comment></comment></comment></comment></comment><comment><USER26> I think the problem in this case is that the author's attempt at generalization went off in the wrong direction.

The fact that fixed-length lists aren't working well as a representation for polynomials is a hint. Polynomials with real coefficients form a vector space [0], so you should really think of them as infinite-dimensional lists of numbers (in which most of the numbers are zero).

Once you know you want to represent an infinite dimensional vector with only a few nonzero entries, you can use a sparse vector. The first library that comes up when you google "Haskell sparse vector" is `Math.LinearAlgebra.Sparse.Vector`, which lets you write something like this (I haven't run this code but it should get the job done):

import Math.LinearAlgebra.Sparse.Vector as V

poly1 = V.sparseList [1, -3, 0, 1]

poly2 = V.sparseList [3, 3]

sumPolys = V.unionVecsWith (+)

So, I read this more as an article about trying to reinvent the wheel in a domain which isn't necessarily simple, which isn't a good idea in any language.

[0]: [https://en.wikipedia.org/wiki/Examples_of_vector_spaces#Poly...](https://en.wikipedia.org/wiki/Examples_of_vector_spaces#Polynomial_vector_spaces)

</comment><comment><USER27> I see this a lot with intermediate lisp programmers; they spend so much time building ivory tower abstractions that the original problem is forgotten. I sometimes call this "bottom down" programming.

Predicting the future is very hard; remembering the past is much easier. If you find yourself typing the exact same pattern for the Nth time, then it's time to refactor it into a macro or a function as appropriate.

Figuring out what parts of the next 1000 lines of code you are going to write will benefit from an abstraction (and which abstraction that is) is a rare skill that comes only (if at all) with experience.

<comment><USER28> "Bottom down" really resonated with me in my dalliances with both Common Lisp and Haskell.

<comment><USER27> I first heard the term "bottom down" from my dad a long time ago, but he used it to mean any sort of programming without a plan. It was many years later that I applied it specifically to people doing "bottom up" but get so obsessed with building the perfect base that they never solve the original problem.

</comment></comment></comment><comment><USER29> The turning point for me was when I realized that these problems exist in other languages and are practically invisible. Without a good type system and inference you cannot hope to catch all of your type errors. You'll just write some unit tests and run your program many times until you're certain you've sussed them all out... until that pesky bug report comes in. Then you get to play detective!

I honestly don't have time left in my life for such meaningless drudgery.

With a type system I have the computer aid me in designing the program. It keeps me honest and ensures that I don't have type errors which are are huge class of things I'd rather _not_ have to think too hard about.

When I program in Haskell I spend more time solving problems than fixing programming errors.

</comment><comment><USER30> In Haskell (and similar), the language offers the ability to really stab genericization in the heart in a good way, to do it the right way. But 90% of the time, you shouldn't and it's very hard not to. Not a matter of restraint, but the language makes it actually very hard to get simple things done unless you plug into the abstraction vortex.

Conversely, languages like Java, C++ and Python (if you use classes), make it very easy to write simple things without abstraction, but virtually all use of abstraction goes off the rails immediately and everything shoots you in the foot, so that _good abstraction_ is not even really a thing at all.

Pick your poison!

<comment><USER31> True but I still manage to go down some rabbit holes in C++.

I could use the older STL iterators, but nooo I use a range, with a lambda. Returning a tuple with tie and pair and some more stuff from the latest C++1x standard.

And in Linux userland, I just want to check a pid but I invent some smart locking system to ensure I never get a false positive or negative.

<comment><USER32> In C++ the main actual rabbit hole of useless abstraction begetting useless abstraction is premature generalization from what you actually need to templates that can be used with types you don't need, which then proceed to kick you with implicit assumptions, type traits, unforeseen subtle type distinctions like those that come up in Haskell.

Other kinds of "stuff from the latest C++1x standard" tend to consist of relatively harmless novel ways to express something, usually not intrinsically complex and, when inappropriate, causing only localized damage (typically puzzling syntax or slightly wrong declarations with no impact on unedited code parts, even in the same class or function).

</comment></comment></comment><comment><USER24> You could also just: write the less general version and stop listening to folks who flip and scoff at every piece of code isn't maximally general.

Crazy, I know, but especially when were doing labor in industry, even without maximal generality your code is probably going to outlive its patron corporation and then die in obscurity.

<comment><USER18> The only person who flips and scoff at every piece of code isn't maximally general is... the author the code. That's the problem.

<comment><USER24> That's not true. There are folks in the community who absolutely DO put pressure on open source libraries to be maximally general (or to use THEIR abstractions over others).

This fosters an environment that might already lead people to second guess themselves, because it's so big and new.

</comment></comment></comment><comment><USER33> I always felt very productive in PHP, because the only rewarding part of PHP is having made something. It never rewarded sophistication... but making a web site that did something WAS rewarding, so all my attention went to that part.

Calling Haskell an anti-PHP seems fair.

<comment><USER34> The same author of the original explores this theme with Java: [https://blog.plover.com/prog/Java.html](https://blog.plover.com/prog/Java.html)

<comment><USER35> That perfectly describes Java (and C#).

It's the land of mediocritity.

</comment></comment></comment><comment> ainar-g >I ought to be able to generalize this

I've never understood this. Unless you write a library that you plan to publish, or already have actual cases where you need a more general solution, why spending time trying to generalise code instead of switching to the next task?

<comment><USER36> My tentative answer is this: someone who uses Haskell appreciates elegant solutions (a.k.a mathematical/functional) and is inclined to write things 'properly' once and they might also idealize that the functions they write will not only solve this current issue, but be useful to others and themselves in other programs ... thus going down the generalization and elegance rabbit hole.

Of course, all of this is purely speculation on my part.

<comment><USER37> Resuming: the typical Haskeller is a perfectionist.

If I allowed, without blinking, my perfectionist self would ditch every language but Haskell. No other mainstream language can give you more control and purity. For a perfectionist this is opium.

<comment><USER38> It is a particular form of perfectionism. Other types of perfectionists might want to be perfect at writing programs as fast as possible.

</comment></comment></comment></comment><comment><USER39> You can eventually "come out the other side" and get to the point where you write the general version correctly the first time. But it is some degree of work. I think it's a good exercise for a pro, but you can certainly live without it.

The general principle does come in handy elsewhere, though. Doing the most useful work with the minimum power is a generally useful skill. I get a lot of mileage out of it in other languages, because across a couple hundred modules, the difference between modules that have minimum dependencies and modules that carelessly overuse power becomes quite substantially different in character.

<comment><USER40> > You can [...] write the general version correctly the first time. But it is > some degree of work. [...] Doing the most useful work with the minimum power > is a generally useful skill.

There's something wrong with that logic, but I'm too lazy to work out the proof in the general case.

<comment><USER39> When people wonder why my typical comments run on to multiple screenfuls, it's because I'm armoring them against this sort of dismissive snark. I was in between tasks today and lacked time to make it longer.

</comment></comment></comment><comment><USER41> I think there's an error in the first example.

      Poly [1, -3, 0, 1]

Should be:

      Poly [1, 0, -3, 1]

EDIT: My mistake.

<comment><USER42> I thought so too at first but given the way addition is defined later on, it makes sense to keep the coefficients sorted by increasing power (the leftmost element in the list is its head, and the easiest to access when doing anything recursive)

<comment><USER43> Evaluation also becomes easy this way, using Horner's method: [https://en.wikipedia.org/wiki/Horner%27s_method#Python_imple...](https://en.wikipedia.org/wiki/Horner%27s_method#Python_implementation)

<comment><USER44> But this doesn't argue for the low-to-high order, because of reversed(). This code would be simpler and faster with the coefficients in the opposite order.

<comment><USER43> You're right, the process does start from the higher coefficients, and so does not really support the ordering presented.

You either need to use foldr to defer the multiply-and-add until the end of the list is processed, or reverse the list before processing it.

</comment></comment></comment></comment></comment><comment><USER45> I am not a Haskell programmer, but is this correct?

        (Poly a) + (Poly b) = Poly $ addup a b   where
           addup [] b  = b
           addup a  [] = a
           addup (a:as) (b:bs) = (a+b):(addup as bs)

Imagine a simple example, adding `x+2` and `10`. In OP's representation, these would be represented as the lists [1, 2] and [10]. That is, the first element is the coefficient of the term of _highest_ degree.

But doesn't this implementation add list elements left-to-right, so we'd end up with the result [11, 2] instead of [1, 12]?

<comment><USER46> You're misreading OP's representation:

> The polynomial x^3 −3x +1 is represented as Poly [1, -3, 0, 1]

It starts with the 0th coefficient and goes up. So adding `x+2` and `10` would be zip-adding lists [2,1] and [10,0].

<comment><USER45> >> The polynomial x^3 −3x +1 is represented as Poly [1, -3, 0, 1]

> It starts with the 0th coefficient and goes up.

Is a list in Haskell canonically written in the opposite order of what I expect? I expect that the 0'th element of the list [a, b, c] is `a`. In Haskell, is it `c`? Assuming `a` is the 0th element, then the coefficient for the highest-degree term is the 0th element of the Poly. And since the degree of the two polynomials doesn't necessarily match, matching up the two highest- degree coefficients and adding them is obviously wrong.

Or am I going crazy here?

</comment></comment></comment><comment><USER47> "Doc, it hurts when I do this." "Don't do that."

</comment><comment><USER48> Similar things happen in other languages. Most recently, I started writing a program in Elm to try it out, realized I wanted to use some CSS, and then got distracted looking at the various ways to do that, with their different tradeoffs. (What is this stylish-elephants package?)

Sometimes it's more productive when you join a team that has already decided on its standards. You don't learn as much, though.

</comment><comment> village-idiot This is me. I have a backlog of personal projects that I've slowly burned through and every freaking time I start with Haskell and end up in Rails. I love working in Haskell ... in theory. In practice I spend way too much time figuring out how to wrangle data into the correct shape when it would've taken me 30 minutes to accomplish in any other language I know, static or dynamic.

</comment><comment><USER49> It's about Scala, not Haskell, but the gist is the same:

at my company we're giving new candidates a live coding interview where they get one hour to write a very simple application using either Java or Scala. Candidates are free to choose between those languages.

The funny thing is, that candidates who choose Scala are never able to fully finish the assignment. Even though the application is really simple, many don't finish half of it and some even get completely stuck in complex for- comprehensions and what not. Candidates who choose Java however mostly are able to finish the assignment. The code might not always be the most elegant, but it does what it is supposed to do.

Even though I like Scala a lot, I feel it has the downside that it gives you too many options to do the same thing. This can get in the way when you are simply trying to implement some basic business feature.

<comment><USER50> So Scala is harder to write, but the question is: is it easier to read?

(Since in general a particular piece of code is read far more often than it is written).

<comment><USER49> That's an interesting question although it's not directly related to the article.

I think it is definitely possible to write Scala code that is easier to read than the same Java code. However it seems that a large part of the Scala community does not see this as their main objective when writing code.

Sometimes the focus seems to be on writing code as terse as possible, which is not the same as readable. Or the focus is on making code more generic and abstract, which can be a useful goal depending on the use case, but it's definitely not the same as readable.

</comment></comment></comment><comment><USER51> Writing elegant code that never works can easily take me twice as long as writing okay code that actually works.

<comment><USER52> You're phrasing that in a seductive way. "Okay code". Maybe that's good enough, right? Maybe not? Someone's "okay code" may be someone else's "bad code". I'm fixing someone else's "okay code" on a daily basis since it's riddled with bugs. Somehow I'd expect that if they would have had the mastery to write elegant code, they may also have been able to make it less buggy, or at least to make it easier for me to fix it.

Also, as with code that's elegant, or well-tested, or specified really well, aside from all those explicit qualities, all of these are also just additional touch moments for the author in question to discover and fix the bugs before it gets handed off, and to become my problem on some future date.

(Not saying you should gold-plate it into elegant code. Just saying that there is value that should not so easily be dismissed.)

<comment><USER51> I think for me, "okay code" means that it's functional, debuggable, and up to professional sniff, but nothing flashy. As opposed to sexy-cool-trendy-meta- wow code.

</comment></comment></comment><comment><USER53> I heard this gem a couple of weeks ago:

"Don't engineer things to failure."

When you find yourself saying "I ought to be able to generalize this", that's when you need to stop and just write the code you need to write NOW. Just because you can, doesn't mean you should.

</comment><comment><USER54> I think the main problem with the specific example is that a list is the wrong data structure to represent a polynomial. Even a simple `IntMap` would be better, where the key is the power.

</comment><comment><USER55> This is clearly overengineering. There is no need to write a generalized function because it is only useful for adding polynomials.

And a function that works only with polynomials will be easier to read.

</comment><comment><USER16> I have to ask: does the author not have the same problem in other languages? If not, why not?

Any major language has dozens of libraries that do almost-but-not-quite what you want. Any language with support for mactos, templates, or generics offers opportunities to write unnecessarily generic code. (The authors of Spring managed to get into that tarpit even before Java introduced generics!)

<comment><USER56> I write in many different languages, but I would say this kind of thing depends a lot on the type of language.

With Go, e.g. I would not spend much time on this, because it is such a plain language. You just accept there is no fancy way of doing this and move on.

With C++ I found it a bit different. Either I mess around thinking there MUST be some way of solving this annoying problem only to realize there just isn't. Other times I find a solution but it tends to turn into a horrible ugly syntax mess, so you abandon it. I've pretty much given up writing anything elegant or fancy in C++. It just turns to shit so quickly.

Swift I found fairly straight forward to write. All the typical stuff that get me stuck in C++, never seems to pose a problem for me in Swift.

Julia is the language which ought to have thrown me into the Haskell problem described, as you can do a lot of crazy stuff with types and macros. I do to some degree but mostly Julia just does what I want it to do. I guess it is partly down to the core functions being well designed and that despite the flexibility it is still not as magical as Haskell, Clojure etc.

</comment></comment><comment><USER57> Polynomial long division in Haskell: [https://github.com/libscott/math/blob/master/src/Math/Polyno...](https://github.com/libscott/math/blob/master/src/Math/Polynomial.hs)

</comment><comment><USER58> In any language, premature abstraction is bad. That applies whether you use type classes in Haskell or classes in Java. It takes experience to judge at a moment's notice whether something is worth abstracting. Beginners frequently get this wrong.

</comment><comment><USER59> There are lots of relevant programming aphorisms: "Write the simplest thing that could possibly work." "YAGNI." "KISS." You either have a problem you need to solve or not. If not, why do you expect the process to ever finish?

This is one area where TDD really shines. You write a simple failing test and implement something that makes that test pass. If that isn't sufficiently generic you write another test, make _both of them_ pass, and refactor until the solution is as simple as possible while the tests pass. Repeat to get to where you need to go.

<comment><USER60> There needs to be a balance. You should choose an architecture which will accommodate predictable future needs without too much refactoring. A suite of unit tests can't help you much if you need to unmangle a bunch of severe abstraction violations between what you now need to be well-encapsulated components.

<comment><USER59> Actual red-green-refactor TDD results in the simplest possible code to solve a problem, IME. Over- or under-abstraction tends to be pretty well instantly recognizable when working with a well written test suite, and can then be easily and safely refactored away.

<comment><USER60> The simplest possible code for the current test suite is not always strategic.

</comment></comment></comment></comment><comment><USER61> 1) to me, this is the difference between haskell and Clojure 2) in the future, normal people will be able to code, so work backwards from that

<comment><USER62> >in the future, normal people will be able to code, so work backwards from that

This.

I'll never be able to understand certain programmers' insistence that imperative code is somehow unnatural or that "we're only used to it because of momentum" or whatever. For thousands of years people have been issuing imperative instructions to each other.

"Wash. Rinse. Repeat."

<comment><USER63> > For thousands of years people have been issuing imperative instructions to > each other.

This ancient culture is pretty strong, you're right. I've lost count of times I begged people to skip all this unreliable "turn right at the second intersection, rinse, repeat" and just tell me the street address long before I learned the word "imperative".

</comment></comment></comment><comment><USER21> Not that representing polynomials as linked lists is by any means ideal, but this "first-guess" program is quite elegant in my opinion.

I know there's a tendency to over-abstract things among the Haskell community, but if you focus on pure, immutable data structures and algorithms on them you'll discover a truly wonderful and indeed pleasant and productive language.

</comment><comment><USER64> > "I ought to be able to generalize this," I say.

lol, it's no wonder he never finishes a program. But this isn't a problem limited to Haskell - one can start generalizing unnecessarily in any language.

To be fair though, the Haskell ecosystem as described in this article (and from my experience) is quite frustrating, and it makes me appreciate my current language Rust that much more.

</comment><comment><USER65> As others have said, go ahead and implement it; you'll have a better idea of what you might want to change or generalize after you have that version to experiment with.

(One case you might want to consider: with that way to create polynomials, won't x^1000000 take a lot of typing?)

</comment><comment><USER66> It's not the abstraction, it's the level of abstraction - the higher you go, the more general and the less concrete it becomes. Striking the balance is the key.

</comment><comment><USER67> This seems like "DFS" programming. I'd advise "BFS". Do it the easy way and put a "TODO: generalize like so."

</comment><comment><USER68> Premature generalization. There.

</comment><comment><USER69> I have this with all languages I get into. I get the urge to radically adopt whatever patterns seem to be idiomatic for the language, whether that's sensible or not.

I tend to judge beginner friendliness of a language by how strong that urge tends to be, and I tend towards Common Lisp since it is very multi-paradigm and not very opinionated, yet with very little semantic warts that bite the user in the end. There are easier languages to pick up if you have no concept of programming (things like HyperTalk or Scratch) but they have obvious semantic deficiencies.

Haskell on the other hand is an excellent first language for structured teaching because it's easy to express concepts in, but it stubbornly resists attempts by the inexperienced or impatient to shotgun or cargo-cult a solution.

</comment><comment><USER70> I've always felt of Haskell that it's a way for very smart people to never get anything done.

I want to like Haskell, I really do, but it's like learning Latin - you'll feel very smart except no one can talk with you except other people that correct your grammar.

Bleh.

<comment><USER71> I write Haskell professionally and I get plenty done :)</comment></comment>