
How it feels to join an all-Haskell startup - begriffs
http://www.wagonhq.com/blog/first-two-weeks-haskell-wagon
======
saosebastiao
How was that snippet an improvement to your coding style? The original was
extremely clear, and now someone who reads your code has to understand what
(,) <$> and <*> do. IMO this tendency for code golf one-upmanship is a huge
detractor for anyone wanting to learn the language.

~~~
thrwwy5
This to me is the biggest barrier to reading anyone else's Haskell code. It
seems like it's always full of unfamiliar, ungooglable infix operators.

~~~
dullcrisp
Try [https://www.haskell.org/hoogle/](https://www.haskell.org/hoogle/).

~~~
thrwwy5
thanks

------
buckie
As someone who also recently joined an all haskell team, but hadn't coded
professionally in haskell before, I'll add the biggest thing I've noticed to
the "how it feels" list:

On a biweekly basis I'm shown something new causing my brain to melt, leak out
of my ear & pool onto the floor near my desk. It's awesome[0]!

Today's was using impredicative types + `$` has a special case for dealing
with it[1].

[0]: ...some number of hours later when I've collected my thoughts and think
"OHHH... duh" [1]:
[https://ghc.haskell.org/trac/ghc/wiki/ImpredicativePolymorph...](https://ghc.haskell.org/trac/ghc/wiki/ImpredicativePolymorphism)

------
dons
Habitually rewriting things in applicative and/or pointfree is a sure sign of
a junior Haskell dev. One who has never had to maintain someone else's code.

There are cases where it helps (e.g. structured parsing), but all too often
this is simply obfuscation. Even if motivation is good -- learning new
structures -- you still have to focus on cost/benefit of each change in
structure.

Keep it simple, folks.

~~~
chriswarbo
I'm generally in favour of introducing applicatives, but I don't think the
code in the article is a good example:

    
    
        (bid, now) <- liftIO $ do
            b <- randomIO
            n <- getCurrentTime
            return (b, n)
    
        (bid, now) <- liftIO $ (,)
            <$> randomIO
            <*> getCurrentTime
    

The applicative code could be considered better, since it avoids one-shot
variables. However, that's not the biggest smell with this code. To me, the
problems are:

\- Constructing-then-destructing a pair; is it really necessary?

\- Use of `$`; is there a way to avoid having to alter the precedence?

\- Combining two seemingly unrelated actions into one; `randomIO` should be
completely uncorrelated to the current time, so why put them in the same
action?

\- Potential laziness issues; it looks like we're using the `(bid, now)`
combination to ensure the two IO actions are executed together, but will they
be? WHNF will give us `(_ , _)`; if we force `bid`, will `now` also be forced?

Not saying I have answers to these, but I would say those are more "smelly"
than the do-notation with a return

~~~
tome
Code review 4 lines: hundreds of comments

Code review 1000 lines: "Looks fine"

~~~
chriswarbo
Well, my main comment is that the most pungent smells in this code depend on
its context and what it's trying to achieve. If I encountered it, I would
immediately look at the surrounding context and usage to see if it's a
reasonable approach to the problem.

Without that context, all that can be done are superficial changes like
monad/applicative; which in this case are very minor. In other words, the
original code wasn't a bad approach to the problem; but is it solving the
right problem?

------
m_mueller
Could someone explain 'applicative'? To me it seems like throwing some magic
syntax at a simple usecase to make it more terse and less readable - but maybe
I misunderstand and it's something every Haskell programmer knows.

~~~
spopejoy
In most cases (like the example), it simply allows you to call "effectful"
code (often monadic, IO etc) to populate arguments of a function.

My favorite example is "I want to grab three web pages _concurrently_ and
return them in a single triple." To the haters who think this is just golf,
just TRY to write this as beautifully in any other language.

    
    
      (page1, page2, page3)
         <- runConcurrently $ (,,)
         <$> Concurrently (getURL "url1")
         <*> Concurrently (getURL "url2")
         <*> Concurrently (getURL "url3")
    

(taken from the excellent haddocks for Control.Current.Async
[https://hackage.haskell.org/package/async-2.0.1.4/docs/Contr...](https://hackage.haskell.org/package/async-2.0.1.4/docs/Control-
Concurrent-Async.html#t:Concurrently))

~~~
doublec
Alice ML:

    
    
        val (page1, page2, page3) = (spawn getURL "url1",
                                     spawn getURL "url2",
                                     spawn getURL "url3")
    

The requests are concurrent. Spawn returns a future and 'page1', etc are
futures immediately. When the value of 'page1', etc is requested later the
requesting process either blocks until the getURL for that value is complete,
or transforms into the value implicitly if it's already done.

I think it's just as nice as the Haskell example. I do agree that Haskell is a
great language though.

~~~
purescript
I don't know Alice ML but one advantage of using abstractions like Applicative
is that you can write code which is polymorphic in the particular applicative
you choose. So, you can mock your concurrent requests using the Identity or
ZipList applicative, and use the type class laws to prove things which are
true about both. I'm guessing, but it looks like the spawn syntax is built-in
here. Not that it's not as elegant as the Concurrent version, but likely not
as powerful from an abstraction point of view.

~~~
doublec
Correct, spawn is built in in Alice ML. Haskell wins on all the ways it can be
used beyond built in functionality compared to it.

------
gohrt
Love it or hate it, those 2 screenshots are life of a Haskeller:

1\. ever-more compact abstractions with awkward names

2\. chasing down space leaks with janky gnuplot'd reports.

------
suls
As much as I would love to use Haskell professionally, I always wonder if
teams/projects using Haskell don't also struggle with all the sociology
involved in developing software ..

Sure, being able to use Applicative reduces lots of code duplication, brings
in better clarity and all .. but what if the product owner still remains a
jerk without a vision?

In all the teams I have been so far, I can honestly say that the _language_
itself was never _the_ problem. It was always a combination of communication,
skill or product vision.

The only thing I can imagine is that by choosing Haskell you tend to get
better skilled developers - so only communication and product vision remain
that could ruin your project/product.

Any thoughts?

