
Show HN: I built a poker site with Haskell - zzeder
https://github.com/therewillbecode/haskell-poker
======
w0utert
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. 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...

~~~
daenz
Haskell 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)

~~~
chowells
Ouch. That function is actually written in a pretty convoluted and redundant
way.

    
    
        getSocketAPIPort :: Int -> IO Int
        getSocketAPIPort defaultPort = do
            maybeEnvPort <- lookupEnv "socketPort"
            return . fromMaybe defaultPort $ maybeEnvPort >>= readMaybe
    

That's starting to border on over-terse, so you could expand the bind operator
into do notation if you wanted to spread it out a bit further. On the other
hand, it's also starting to feel over-verbose, using do notation for only a
single IO action. Maybe...

    
    
        getSocketAPIPort :: Int -> IO Int
        getSocketAPIPort defaultPort = fromMaybe defaultPort . (readMaybe =<<) <$> lookupEnv "socketPort"
    

That might be going too far. But maybe it's what I'd write. Just depends on
how much I expect to make this more complicated in the future. This form has
the simplest flow to read. I mean... it's dense. Really dense. But it has the
fewest total things going on, and it neatly divides into three interesting
parts, easily understood in isolation, plumbed together with two common
combinators. But it's also pretty rigid in structure. If you ever want to add
other sources for finding the port or change the priorities of them, that form
would need to be totally rewritten, and probably would end up back in do
notation.

But in every case, all the various return calls should be combined into one
(or none, if you use fmap or <$>), and the fallback to the default should only
be written once.

~~~
danidiaz
In your first version, I think I would use =<< to keep "flow" of information
right-to-left. I also use parentheses instead of . and $ when there isn't a
lot of nesting, I got that habit from this post about writing legible Haskell
[http://www.haskellforall.com/2015/09/how-to-make-your-
haskel...](http://www.haskellforall.com/2015/09/how-to-make-your-haskell-code-
more.html)

    
    
        getSocketAPIPort :: Int -> IO Int
        getSocketAPIPort defaultPort = do
            maybeEnvPort <- lookupEnv "socketPort"
            return (fromMaybe defaultPort (readMaybe =<< maybeEnvPort))
    

Keeping the pattern match instead of using "fromMaybe" wouldn't be a bad idea,
either:

    
    
        getSocketAPIPort :: Int -> IO Int
        getSocketAPIPort defaultPort = do
            maybeEnvPort <- lookupEnv "socketPort"
            return (case readMaybe =<< maybeEnvPort of
                Nothing   -> defaultPort
                Just port -> port)
    

It makes the default value stand out a bit more.

~~~
nilkn
I've written a fair bit of Haskell, including some production software. Your
second version here is my personal favorite of the variants proposed so far.
It's the version I can look at and more or less instantly understand. I think
sometimes folks go a little too far with using library functions to manipulate
Maybe values -- not that `fromMaybe` is particularly onerous, but something
about the structure of pattern matching just conveys information to my brain
much faster.

------
_hao
Trying 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?

~~~
whateveracct
In 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.

------
patientplatypus
Dumb 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
It’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.

------
jgwil2
Very 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 ;)

------
kodablah
Go 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)

------
InvOfSmallC
What would be the best IDE/editor for Haskell?

~~~
marcosdumay
Emacs works very well. Haskell is the second best emacs experience I've ever
had, second only to Lisp.

Things were not always this way. Just a few years ago, it was a bad
experience, so if you have bad memories, it may be time to try again.

~~~
claudiawerner
I used Haskell on Emacs a few weeks ago and there still seems to be some
issues with regards indentation.

~~~
marcosdumay
Ouch, it has been so long that I have forgot about this. Add this to your
emacs init script somewhere:

    
    
        (add-hook 'haskell-mode-hook 'turn-on-haskell-indentation)
    

It is also not compatible with older versions of intero and haskell-mode, so
if you have old configuration there, you may want to remove it.

Honestly, it's even weird this isn't on by default.

~~~
tome
That's strange. I don't have anything like that in my .emacs but I do get
indentation automatically for Haskell files. I do have a recent dante-mode
though. Perhaps dante-mode turns it on automatically?

------
kreetx
I 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?

------
anardil
Very 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
Yes 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.

~~~
anardil
That'd be great! I saw some todos, but you'll have the best perspective on
what's important. I'm
[https://github.com/Gandalf-](https://github.com/Gandalf-)

~~~
zzeder
Ok I have added some things to work on to the issues. Feel free to pick one up
or add your own. :)

------
stephen82
zzeder, 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

------
platz
piling on... I build a bookmarking site (self-hosted) with Haskell
[https://github.com/jonschoning/espial/](https://github.com/jonschoning/espial/)

------
charlescearl
What are good Haskell codebases (or videos) to read through if you have a
passing knowledge and want to improve?

~~~
gilmi
Check out this list of applications written in Haskell:

[https://github.com/soupi/haskell-study-plan#a-few-cool-
open-...](https://github.com/soupi/haskell-study-plan#a-few-cool-open-source-
applications)

