6 ms·
Implementing 2048 in 90 lines of Haskell
- leoh 12y agoQuestion: I've seen at least several succinct versions of programs written in Haskell. Would people say this is a benefit of Haskell? Just skill on behalf of the coder?
- gu 12y agoOne of the benefits of Haskell is indeed that this language makes it possible to write very expressive code. The same is true for other functional languages as well. However, this won't happen automatically. In other words, it will take some practice. You can certainly write convoluted code in Haskell.
- vamega 12y agoYes, one of the worst mistakes I've seen people make is trying to write Haskell exactly like you write code in other languages like Python. If you ignore the power of Haskell's type system, and write all your code imperatively in the IO Monad, and continue to write large functions that do many things instead of writing smaller functions that can be composed, you gain almost nothing from Haskell, and you might have been better off writing your code in another language.
- freyrs3 12y ago> you gain almost nothing from Haskell, and you might have been better off writing your code in another language. Don't know about that. Even if you write everything in the IO monad, Haskell is still a pretty great imperative language and many people say it may possibly one of the best imperative languages ever written. If you only use IO, then yes, you no longer gain the ability to reify and isolate effects as values but all the other strengths of Haskell's type system mostly remain invariant and just as useful.
- dbpatterson 12y agoI think it's a little bit of both. Yes, Haskell code is often quite terse, but the more important thing is that the type system allows abstraction to a much higher degree than in languages with weaker type systems. Abstraction always takes skill, but in Haskell usually once you come up with the abstractions, the type system allows you to (pretty easily and) safely use them.
- brandonbloom 12y agothe type system allows abstraction to a much higher degree than in languages with weaker type systems That may be true, but that's simply irrelevant in this case. The type system is not being used in [1] for any interesting searches (proofs, return type polymorphism, overload resolution, etc) here outside of the most trivial of polymorphic literals. Every standard library function in use here works practically identically in any functional language, including dynamic ones such as Clojure. https://github.com/gregorulm/h2048/blob/master/h2048.hs https://github.com/gregorulm/h2048/blob/master/h2048.hs
- taylorfausak 12y agoNeat! I also cloned 2048 in Haskell [1]. I don't know how many lines of code it is, but the core game logic is remarkably simple. [1]: http://taylor.fausak.me/2014/04/28/cloning-2048-in-haskell/ http://taylor.fausak.me/2014/04/28/cloning-2048-in-haskell/
- jabagawee 12y agoI noticed that your blog post differed from the actual code in your git repository. In the blog post, you defined `shift` to be: shift v = pad (map Just (concatMap add (group (catMaybes v))))) Nothing (length v) whereas the code gives: shift v = take n (v' <> empty n) where n = length v v' = group (filter isJust v) >>= go go (Just a : Just b : ts) = Just (a + b) : go ts go ts = ts From my understanding of the blog post's logic, the former doesn't handle the case where `v = replicate 4 (Just 2)`, since it returns `[Just 4, Just 2, Just 2, Nothing]`. Am I correct, and if so, why does the latter version fix this problem? For reference, I know little to no Haskell.
- taylorfausak 12y agoWow, excellent catch! I apologize for the discrepancy. I must have made a mistake simplifying the game code for the blog post. I created a Gist [1] to showcase the differences. The problem in the blog post is the `add` function. It should recurse (like `go` in the Hs2048 package). I fixed the post [2] with this line: add (x : y : rest) = x + y : add rest [1]: https://gist.github.com/tfausak/4401ef0b43b5c1db0570 https://gist.github.com/tfausak/4401ef0b43b5c1db0570 [2]: https://github.com/tfausak/tfausak.github.io/issues/31 https://github.com/tfausak/tfausak.github.io/issues/31
- jabagawee 12y agoOh! So `go` is a function that's defined within `shift`. That's the crucial part I was missing. Why is it named "go"? EDIT: While I have your attention, do you mind also pointing me to some resources to learn about this ">>=" operator? I recall it's something related to monads...
- taeric 12y agoThis is neat and all, but the smooth animations of the original are probably not something you can easily pull off in few lines of code. And that is a very large fraction of the original, if I recall.
- gu 12y agoThe smooth animations in Gabriele Cirulli's version are due to this API: https://developer.mozilla.org/en/docs/Web/API/window.requestAnimationFrame https://developer.mozilla.org/en/docs/Web/API/window.request... They consist of a few lines of code. Further, the animation code is only a miniscule fraction of that code base.
- taeric 12y agoNot entirely sure why you are getting voted down. (Well, unless you are wrong...) :( I'll have to dig through the code again. The polish that the end product of the first version exhibited is well beyond that of any of the rewrites I've seen. To the point that it is, in fact, jarring. And makes it frustrating to read how much nicer the code looks in some of them. Really brings home the point that intrinsic quality is nice, but pails in comparison to the final quality of the overall product. It isn't that I am convinced the sausage making process is always gross. Just that I have not seen that many examples where the clean versions are anything more than just sterilizations that have killed a lot of the original.
- gu 12y agoWho knows, maybe my comment made some "full stack" developers feel insecure. Just look at the code base of the original, and you'll see that the animation is done through API calls. Regarding the point you brought up: you are conflating two issues. One is whether the UI is appealing, and the other whether the underlying code is of a high quality. The point of my article was merely to show how nicely the game logic can be expressed in Haskell, compared to many other languages.
- taeric 12y ago
- cwhy 12y agoI haven't used haskell before and did not fully understand the code, but since python support those map filter stuff, can we write haskell-like python as well?