13 ms·
Show HN: I built a poker site with Haskell
- w0utert 7y agoSo, I know literally nothing about Haskell, and I would rate my knowledge of functional programming theory as 'beginner' at best, but I still get baffled every time when reading Haskell code that implements anything other than something trivial like a fibonacci sequence. The poker server code looks extremely tidy and well engineered, so that can't be the problem, but to me it's utterly incomprehensible. It seems like every expression implements 20 different things at the same time, which makes it really hard to decode what is going on. Is it just me, or is this typical for all non-trivial Haskell code? I don't have any problems interpreting e.g. Clojure, or Javascript written in a functional style for that matter, but Haskell...
- anchpop 7y agoI think part of the problem is that Haskell code can be very terse. When reading Python I expect to be able to easily understand what's going on in a 5 line function because the pythonic style limits what you can do in 5 lines. But in haskell a 5 line function can be pretty sophisticated.
- chucky_z 7y agoCareful about sweeping generalizations... The internet has shown what is possible in "one line" of python, and I've seen this in the real world scarily enough!
- jakear 7y agoWhat you can accomplish in 5 lines of “ready for production, maintainable, easily understandable by coworkers” python is vastly less than what you can accomplish in 5 lines of similarly constrained Haskell.
- thedufer 7y agoUnfortunately, a lot of work there is done by the Haskell community having utterly absurd standards for those things. I work in a different functional programming language, and you would not believe the amount of time I spend convincing new hires with Haskell backgrounds to spend the extra few characters to expand out the unreadable point-free/single-character-names style that Haskell folks prefer.
- jakear 7y agoOh believe me, I’d believe. My Haskell background comes from building upon academic proofs of concept during a stint at CSAIL. Never again.
- KirinDave 7y agoThat world has very little to do with commerical Haskell though, now does it? Why, we even discourage the use of Singletons and if you import a unification library everyone will immediately demand to know why.
- chowells 7y agoHas it ever occurred to you that Haskell programmers prefer single-letter variable names in some contexts because it makes the code better? Perhaps it is not the children who are wrong.
- anchpop 7y agoRight, I find pointfree style to be much more readable than pointful, I expect the GP would too if they became used to it
- jakear 7y agoThe problem is you can’t bring that change about in a corporate setting by just doing things your own way and hoping your coworkers catch up. I think that’s more what GGP was having issue with.
- AzzieElbab 7y agoHaskell is not a difficult language to learn, but unlike imperative languages, you can't just start reading the code if you "know literally nothing about Haskell". One thing to keep in mind is that every other line in Haskell is basically just composing functions together, but you need to know how all those weird >>= and <*> and <$> effect code/composition flow
- preommr 7y ago> is not a difficult language to learn People say this about every single programming language.
- AzzieElbab 7y agodunno. to me PHP and CPP are the hardest, because I cant figure out the logic behind their design.
- 6gvONxR4sf7o 7y agoSome have genuinely uniquely confusing bits. Like `this` in javascript. Or `Hold` and `Evaluate` in mathematica.
- KirinDave 7y agoProbably because they're all right.
- daenz 7y agoHaskell is dense. I'm picking it up now[0], so this project was very useful for me to see how some "real world" Haskell is written. But yes, take for example this function getSocketAPIPort :: Int -> IO Int getSocketAPIPort defaultPort = do maybeEnvPort <- lookupEnv "socketPort" case maybeEnvPort of Nothing -> return defaultPort Just port -> maybe (return defaultPort) return (readMaybe port) It gets a port from an environment variable, if it can, otherwise a default port. Conceptually, this is easy to understand, but translating your understanding of that process to Haskell is not 1 to 1. For example, the last line alone: Just port -> maybe (return defaultPort) return (readMaybe port) You have to understand Maybe (and failure contexts), you have to understand that "return" does not return from a function like typical imperative languages, instead it wraps a type in a Monad (in this case, the IO Monad), and you also have to understand that most of those things on that line, including the "return" function, are parameters to the "maybe" function. There's a lot to understand in terms of the underlying machinery of Haskell to be able to read its cryptic flow and syntax. But it is worth it imo. 0. http://learnyouahaskell.com http://learnyouahaskell.com
- hombre_fatal 7y agoThough notice that you picked literally the most trivial example in the entire codebase that anyone can understand without explanation. Elm is onto something with its obsession with simplicity and lack of features. I go back to old Haskell code and have to completely recredentialize in Haskell before I remember what's going on. I return to old Elm code and need very little ramp up. I'm not making an "Elm > Haskell" argument, I just think experimentation with simplicity does this family of languages a favor.
- jecxjo 7y agoDo you have a better example from this code base? I'm looking but unfortunately I'm not seeing anything that isn't either trivial or just a lot of monad stack handling.
- hombre_fatal 7y ago
- the_af 7y agoIt's not a good idea to try reading Haskell by "brute force", trying to figure it out as you go. I suggest you first read through something that teaches you the basics like "Learn You a Haskell" or similar. In a way, the experience is more like Clojure than Javascript. If you've read a Java-like language before, figuring another one tends to be easy. But if you've never read a Lisp-like, all the Java-like experience in the world won't help you to read a non-trivial Lisp program. You will just see some weird parentheses and won't be able to make head or tails of it. Haskell is similar. Some upfront learning is needed before reading non-trivial programs.
- doctorpangloss 7y agoGame servers aren’t typical. Texas Hold’Em especially. Like a chat application is also multi-user real-time. It’s obvious that when a chat participant disconnects you hold onto the messages to deliver to them for later. When you disconnect from a Texas Hold’em online and you were small blind, what should you do? Wait? Shift the blinds over? The next player in line gets big or small? Copy the leading product’s behavior? It’s hard to reproduce all the states in someone else’s live, production game. It’s not at all obvious and this logic has to live somewhere. It touches a bajillion things, like the raw connection state, timers, transient and long-term persistent state. Your programming language isn’t going to make it simpler for you. It can’t just hide in your database’s conflict resolution or some AWS service. This is a great Haskell demo because it shows that you can’t hide this code anywhere. It stares back at you with all its ugliness.
- shoo 7y ago> This is a great Haskell demo because it shows that you can’t hide this code anywhere. It stares back at you with all its ugliness. i enjoyed your comment and these last two lines in particular. different programmers might interpret these lines in completely different ways: one as a critique of haskell for not being able to tidy the details away to make the code appear simpler, another as praise of haskell for making these mechanics explicit.
- verttii 7y agoOur ways to hide that logic has been building libraries that handle nearly all of it. But since Haskell's ecosystem is small by comparison a lot of that logic leaks to your own application code. Especially when dealing with something like stateful websocket applications.
- twitchard 7y agoA general-purpose library able to hide the necessarily specific logic of how network events and a poker game should interact seems... unlikely?
- 7y ago
- whateveracct 7y agoThe nice thing about Haskell from a readability standpoint is to unpack what code does at any point, you only have to perform substitution (i.e. beta reduction) over and over. This is a key difference from most other programming languages, which require you to have a little VM in your head. "Localized reasoning" is what Haskellers call this. To read it quickly, you do have to learn & internalize abstractions. Both a common set of them (the usual type classes) & abstractions custom-built in your project. Abstractions in Haskell tend to be true abstractions & not encapsulations. You don't necessarily need to know the internals to understand the abstraction. I've seen this put off systems programmers before (people used to writing C etc and understanding the assembly). I wouldn't expect someone with no Haskell knowledge to understand Haskell code. I've seen higher-level people (e.g. VPE-level) get upset by this and knee-jerk decide Haskell is problematic. I'm of the opinion that such knee-jerks aren't worth listening to..I don't care about opinions of people who haven't met (or honestly tried to meet) the prerequisites. Regardless, I will say as someone who has learned Haskell: Once you learn it, it becomes so stupid easy to do everything. I feel like I can solve more complex problems faster & better in Haskell than other programming languages I have comparable (or more!) experience in.
- verttii 7y agoYou mean that decomposing abstractions with substitution works better in Haskell than in a lot of the other languages because programs in Haskell are essentially (pure) functions and abstractions are built by composing functions?
- whateveracct 7y agoYeah - referential transparency is what allows it to Just Be Substitution.
- elwell 7y ago> Is it just me[?] It's not just you, I came here to say the same thing. I just feel dumb when I try to read Haskell, though I've been using Clojure in production for over 5 years.
- friedbrice 7y agoWhile I feel like writing Clojure for 5 years would improve one's ability to /write/ Haskell, I feel it'd have almost no impact on one's ability to read Haskell. With all pros (e.g. local reasoning, referential transparency, no destructive updates) and all cons (e.g. tons of marshalling/converting, piles of imports, shitty records) aside for a moment, I think you learn to read Haskell like you learn to read any other programming language: by writing a lot of it.
- 6gvONxR4sf7o 7y agoOne problem is very generic tooling in Haskell. In many languages, you'll have a library that might provide a function like "iteratePokerGameStep." In the haskell community, the author is more likely to realize that this could just be implemented via "BiApplicativeProfuctorCategory.map." So instead of writing a 6 line "iteratePokerGameStep" which gets its own name, you're more likely to see someone just call "map." Much simpler code in some ways, much less simple in others.
- KirinDave 7y ago"BiApplicativeProfuctorCategory". Please don't just make things up.
- dllthomas 7y agoIf it's not obvious why someSuperGenericThing is thisSpecificThingINeed in this case, I'll often give it an appropriate name and more specific type locally. It helps the next reader (which, of course, might be me) and can also help keep type errors better localized. It takes noticing, though, to be sure.
- johnday 7y agoThis is very good style.
- KirinDave 7y ago> So, I know literally nothing about Haskell, and I would rate my knowledge of functional programming theory as 'beginner' at best, but I still get baffled every time when reading Haskell code that implements anything other than something trivial like a fibonacci sequence. Then perhaps you should fix these before indicting the code? Haskell isn't just a different language to learn because it's different, it's also a different language because it has a community that values math-driven models of things. As such, you're going to end up at a disadvantage trying to understand every aspect of it without any prior consideration. Sorta like how templates often baffle new programmers but are considered absolutely essential by folks who get a year or three of C++ experience.
- quickthrower2 7y agoAs someone who learned Haskell in their spare time: Yes you are correct sort of. I'd say 50% of the reason it's hard to read is you are not familiar and 50 hours of learning Haskell would sort that out. Training your visual memory to get used to (f a b) rather than f(a,b) etc. I liked to add redundant parens in my play code just to help me with this. The other 50% is those damn library authors and their love of funny operators and advanced GHC extensions. And also some people like to play code golf with "point-free" style where instead of the x -> f x you'd just use f. Which if taken to the extreme produces hard to read code that is lovingly called "pointless". Code golf in Haskell is rife. I really prefer longAndMeaningfulVariableNamesThatErrOnTheSideOfBeingTooLong, but the Haskell culture isn't that way, and they prefer names like: s'.
- anardil 7y agoVery neat! I've been working on a network application in Haskell too; this is a great reference. Is this project still active? Are there some features you'd like help developing?
- zzeder 7y agoYes this project is active. That would be awesome if you contributed. There are a lot of features to add. Would you like me to add some of these to the issues on Github? Feel free to add your own suggestions to the issues as well.
- jgwil2 7y agoVery awesome-looking project! I think this is the kind of thing that Haskell needs more of: networked application code that is tangible and can give more curious folks (like me) an idea of how this language might be useful for our own projects. Edit: only thing missing is PureScript on the frontend ;)
- kreetx 7y agoI see you are using ekg. I've written quite a lot of haskell, but haven't ever used that, but have been curious - how much does it help you, or is it just for fun/test?
- InvOfSmallC 7y agoWhat would be the best IDE/editor for Haskell?
- namibj 7y agoYou can use a language server with Atom. Beware of stuff breaking (barely any ABI compatibility), and it taking like 12G ram, however. Otherwise you can also integrate a language server with Vim or Emacs.
- dbelford 7y agoI'm curious about this too. Every once in a while I try going through the editor setups in this chart - https://github.com/rainbyte/haskell-ide-chart https://github.com/rainbyte/haskell-ide-chart. But I run into lots of friction in any one I try. Between using the REPL, getting harmony in the project libraries and the IDE engine libraries, and learning a new editor, I run out of energy to also learn the language ecosystem (libraries, concepts, idioms, package managers). An IDE that that surfaced everything the language encodes seems like it would lower the learning curve of Haskell. And every year it seems a little closer. Is there anything close to a jetbrains/visual studio/xcode yet? It seems like all the type safety would be valuable enough that companies would pay for/invest in the ecosystem. Learning the ecosystem has been more challenging than learning the language at this point for me.
- c3534l 7y agoVim.
- jolmg 7y agoYup, that's what I use. Just like for any other language, it works great.
- mrkeen 7y agoAnything that highlights other instances of what you highlight yourself. My pick is Kate on KDE. But I've been using vscode as well so I'm not tied to OSs that can run Kate.
- 7y ago
- _hao 7y agoTrying to read Haskell code without any knowledge of it is interesting to say the least. I like how compact it looks, but I'm guessing a lot of the simple looking statements (at least at first glance) do a lot under the hood. Is that a characteristic of Haskell itself or just the developer has a good style?
- c3534l 7y agoHaskell tends to be terse because a number of features and very general built in functions. The author is also good at Haskell and lacks a lot of ugly optimizations making it look even cleaner.
- whateveracct 7y agoIn Haskell vs other languages, a large amount of your program is written using various forms of composition (function composition, applicative/monadic composition [sequencing of side-effects], monoidal composition [combining values], library-specific composition [e.g. Conduit =$=] etc). The stuff you compose tend to be small functions that are easy to test & reason about. The nice thing about composition in Haskell is that if you have correct program A & B, then the composition of A & B is also correct & easy to reason about.
- charlescearl 7y agoWhat are good Haskell codebases (or videos) to read through if you have a passing knowledge and want to improve?
- gilmi 7y agoCheck out this list of applications written in Haskell: https://github.com/soupi/haskell-study-plan#a-few-cool-open-source-applications https://github.com/soupi/haskell-study-plan#a-few-cool-open-...
- duijf 7y agoIf you haven't seen https://haskell-at-work.com/episodes.html https://haskell-at-work.com/episodes.html yet, I can recommend it
- platz 7y agopiling on... I build a bookmarking site (self-hosted) with Haskell https://github.com/jonschoning/espial/ https://github.com/jonschoning/espial/
- patientplatypus 7y agoDumb question. Is Haskell ever the best tool for the job? I feel that every language has a sweet spot, but Haskell seems to be a language that people use just to show that they can. I've always wanted to learn, but I don't want to learn if there isn't a reason to.
- nvarsj 7y agoIt’s arguably the best pure functional language implementation. So if you think functional programming is a good thing, then yes it’s worth learning. The worst part about Haskell is you realise how lacklustre functional programming is in every other hybrid language. The lisps probably come closest in capturing a similar feel.
- whateveracct 7y agoOnce you get over the learning curve, Haskell becomes the best tool for most jobs. The main reason I've _not_ used it is ecosystem (e.g. if Go or something has a library for some API that Haskell doesn't) For instance, you could make a video game in Haskell. It has SDL2 bindings, plenty of networking libraries, best-in-class support for DSLs (user scripting), and you can even write the music for your game itself in Haskell!
- 6gvONxR4sf7o 7y agoHere's a popular "State of the Haskell ecosystem" page: https://github.com/Gabriel439/post-rfc/blob/master/sotu.md https://github.com/Gabriel439/post-rfc/blob/master/sotu.md There are a number of things where haskell is best in class and a larger number of things where it's immature. The language itself could be excellent at far far more than it is today, but libraries are limited for many tasks.
- kodablah 7y agoGo one further and implement Mental Poker [0] so the server doesn't have to be trusted. I wrote an implementation in Go [1] when I was toying w/ p2p card games. 0 - https://en.wikipedia.org/wiki/Mental_poker https://en.wikipedia.org/wiki/Mental_poker 1 - https://github.com/cretz/go-mental-poker https://github.com/cretz/go-mental-poker
- stephen82 7y agozzeder, I would like to thank you for posting this, because after browsing your code, I finally found the excuse I was looking for to teach myself Haskell; so far I'm not only enjoying it, but I sincerely loving it and have finally realized I should have learned FP in the first place! For once again, thank you mate! +1