News for hackers. Stuff that matters.
Re:Haskell in Production by microtherion on Thursday October 17, 2019 @06:02PM (#21286751)
So if somebody asserted that INTERCAL-72 is the proper language to use for production code, you would consider it unfair to contradict them until you've used INTERCAL in production code yourself?

Personally, I would not necessarily disbelieve somewhat propagating Haskell as a production ready language. However, I'm fairly confident that it would be thoroughly unsuited to any areas of work I regularly operate in.

I have tried a number of times to learn Haskell (from a variety of tutorials and text books). I find myself nodding along sympathetically at the fundamentals (functional purity, non-strict evaluation). I can follow the initial chapters. And somewhere between "Functor" and "Applicative", I tend to lose the plot.

Then I look at supposedly real world code like the URL shortener in Allen/Moronuki's "Haskell Programming from First Principles", and I just can't make heads or tails of it: https://github.com/bitemyapp/shawty-prime/blob/master/app/Ma...

   app :: R.Connection
       -> ScottyM ()
   app rConn = do
     get "/" $ do
       uri <- param "uri"
       let parsedUri :: Maybe URI
           parsedUri = parseURI (TL.unpack uri)
       case parsedUri of
         Just _  -> do
           shawty <- liftIO shortyGen
           let shorty = BC.pack shawty
               uri' = encodeUtf8 (TL.toStrict uri)
           resp <- liftIO (saveURI rConn shorty uri')
           html (shortyCreated resp shawty)
         Nothing -> text (shortyAintUri uri)
If that's supposed to be the way to write production code in the future, count me out!
Re:Haskell in Production by whateveracct on Thursday October 17, 2019 @06:34PM (#21286961)
What exactly is wrong with it? I've never even used the Scotty library or monad being used and I can understand it.
Re:Haskell in Production by microtherion on Thursday October 17, 2019 @07:12PM (#21287218)
1. I have a vague idea what the second "do" is for. I don't have the slightest idea what the first "do" does.

2. I have some idea what "$" is, but I have no idea what it does in this context.

3. param "uri" is presumably extracting a parameter, presumably from the result of an incoming HTTP request. How is that request passed into "app"? How is it passed into the "get"? How is it passed to "param"?

4. Why does "parsedURI" need a type signature?

5. "Just/Nothing" more or less makes sense, but "Left/Right" (used outside the excerpt I quoted) is a notation that makes about as much sense to communicate meaning as "car/cdr" does in Lisp.

6. A response is generated. How does that response get back to the client?

7. What does liftIO do?

8. The overall syntax is just a pile of wrongness. There are left pointing arrows and right pointing arrows, which have completely different (and entirely non-symmetric) functions. There is an equals sign, which has a somewhat similar role to a left pointing arrow, but for some reason needs a completely different operator. There is a right pointing arrow in the function signature which is completely unrelated to the arrow in the case statement. There is an empty pair of parentheses doing Curry knows what. There are return values, which you can identify by following the peaks and valleys of the indentation.

So, TL;DR, this is an incomprehensible control and data flow, wrapped in an ugly syntax.

Re:Haskell in Production by phlakaton on Thursday October 17, 2019 @10:53PM (#21288270)
At the risk of proving your point (this part of the code is indeed a bit of a hash), but in the hope that this will help a little with learning, here are some answers:

1. The first do in your snippet does nothing - it's redundant. In the actual code you linked, though, it sequences the `get "/" ...` and the `get "/:short" ...` expressions into a single application initializer. When the app starts up (i.e. when `app` is called), this outer "do" runs through your endpoint-defining expressions and registers each endpoint in turn with the HTTP server.

2. That `get` function takes two arguments: the URI pattern and the action to run if the pattern matches. The whole rest of your snippet _is_ the second argument! Because of the low precedence of the "$" operator, using "$" means you don't have to enclose all that code in parentheses. It is a tiny bit of syntactic sugar that is wildly popular in Haskell-land because Heaven forfend any of your code ends up looking like LISP. ;-)

3. The answer is in the monad being used in this case to sequence these steps together (`ActionT Text IO <some return type>`). Think of `param "uri"` not as an expression returning a string, but a partially-constructed function that takes an HTTP request as an additional argument. The monad takes care of threading the request into this function when the request is actually handled, and `uri` will be bound to the resulting value.

4. I'm guessing it doesn't. Many type signatures in Haskell are optional, and are added if either 1) there's a genuine ambiguity in the code that needs to be clarified, 2) the author thinks it will make things clearer, or 3) the author hit a bug where the compiler inferred some crazy generic type that the author didn't intend or understand, and they put in some type signatures as sanity checks and constraints on what type is actually expected.

Re:Haskell in Production by microtherion on Friday October 18, 2019 @05:36PM (#21295272)
Thanks for your explanations! 2&4 make a lot of sense. 1, and even more so 3, lead to more questions than they answer, in my opinion. Monads appear to be an absolutely indispensible aspect of most substantial Haskell programs, but to me, they just look incomprehensible. I understand the advantages of a pure programming model for formal reasoning about programs, but in terms of communicating an intent with a program, I can't help thinking that the cure offered by Monads is far worse than the disease of mutable state.
Re:Haskell in Production by phlakaton on Friday October 18, 2019 @09:52PM (#21296329)
The advantage of monads is that they whisk away a bunch of boring, repetitive boilerplate code that nobody wants to write and that people will even go so far in other languages as to create a bunch of global/thread-local/hidden-context variables to avoid writing!

The downside is that the abstraction and its applications, maybe a bit like pointers, do take a while to really master. Particularly when you start composing monad types to make other monads, as Scotty does with IO.

Re:Haskell in Production by whateveracct on Thursday October 17, 2019 @08:03PM (#21287488)
Look, I sympathize with you because Haskell is not easy to learn by any means so I understand someone not liking it. If I get time later I'll go item-by-item and explain. There's a lot of questions there but it's actually just a few fundamental concepts.

But I've seen engineers with only C/C++ experience get onboarded and write code with the same concepts & more complicated ones as the link shortener above. The key was onboarding by someone who knew Haskell well. Haskell companies need a culture of learning _and_ teaching to truly thrive and counteract downsides of the language like hiring pool and learning curve.

Re:Haskell in Production by sullyj3 on Friday October 18, 2019 @12:26AM (#21288681)
> I don't have the slightest idea what the first "do" does.

We know from the type signature that it returns a `ScottyM ()`, whatever that means. We don't know what that entails without having looked at the documentation. I don't think it's fair to criticize it on this basis, though, it seems basically the same as when you see an unfamiliar function in some python code and have to look up what it does.

However when we look at the docs: http://hackage.haskell.org/package/scotty-0.11.5/docs/Web-Sc...

There's literally no documentation for this type. Imo this is emblematic of a pretty dysfunctional culture in haskell of not bothering to document things properly.

By ctrl-f-ing "ScottyM" and looking around the page we can see that it's returned by the `get` and `post` functions, and get a vague idea that it's the type used to progressively build up a scotty web application. Then we see that the `scotty` function takes a `ScottyM ()` and returns an IO () that we can run as the main function of our program.

It can definitely be figured out, but the docs sure don't help much.

> this is an incomprehensible control and data flow, wrapped in an ugly syntax.

Parts of it are pretty bad, but I don't think the control flow being quite implicit here is actually much of a problem. Scotty is based heavily on Sinatra, a minimal ruby framework, and it kind of reminds me of Flask as well. In all of these, it falls to the programmer to decide what to return on a given route, and the sending back of the data is all handled implicitly and invisibly by the framework. So, I don't see this as an issue, and, if it is one, it isn't Haskell specific.

Re:Haskell in Production by whateveracct on Friday October 18, 2019 @12:46AM (#21288763)
We can quickly find out that ScottyM is a Functor/Applicative/Monad though. And in this code (and using this library in general), that's all we need to know! FAM is a universal interface.
Re:Haskell in Production by sullyj3 on Friday October 18, 2019 @07:30PM (#21295862)
Knowing you can <$> <*> >>= doesn't mean you know what something does/what it's for though.
Re:Haskell in Production by whateveracct on Friday October 18, 2019 @10:11PM (#21296378)
But it typically tells you how to compose such a thing, especially if it's 100% abstract to begin with (like Scotty.) It just becomes type Tetris.
Re:Haskell in Production by phlakaton on Thursday October 17, 2019 @11:14PM (#21288354)
As to the rest:

5. Completely agreed, especially since, semantically, it's almost always used as "Error/Success". Silly naming aside, though, it's extremely similar to Maybe, except that the failure case can contain a value (an error message, for example).

6. Think of your entire "action" (the second argument to get) as a function that takes a request and returns a response. Scotty takes care of invoking your action as necessary when a request comes in, and it also handles writing the response out for you.

7. liftIO takes an `IO String` computation as input, and transforms it into an `ActionT Text IO String` computation. This is done about the stupidest way possible: it returns an action that ignores the input request, generates a string, and "returns" it. liftIO is a heavily overloaded function that is defined for lots of monads that can easily incorporate IO computations, usually because they themselves are nothing more than dressed-up IO computations.

8. Yes, -> and <- are very different, and -> is overloaded. = and <- are very different because the latter relies on a monad to define how a value is extracted from the right-hand side and fed to the next part of the computation. The empty pair of parentheses is like void in C - a function with a return type of () doesn't return any value. In the case of our HTML actions, an action of type ActionT Text IO () may have a side effect of writing a lovely HTML response, but it doesn't produce a value like `param "uri"` does - it just does the side effect and it's done. Yes, indentation is important in Haskell, it's less regular (or you might say "more expressive") than in other languages, and in the code you linked it looks like it got jumbled somewhere along the way.

Re:Haskell in Production by wolco on Thursday October 17, 2019 @08:51PM (#21287715)
Could be a fun game. I'll guess. No haskell knowledge. PHP background.

1. Connect to remote connection. DO - wait..

2. $ Loop-over

3. It comes from a config file with a hardcoded value and is globally included

4. Because it could be reused to handle a different types.

6. Text is printing to standard output.

7. Creating and Repointing the response to the resp var

Re:Haskell in Production by dragonwriter on Friday October 18, 2019 @09:36AM (#21291221)
The only thing I see bad about that code is some bad variable naming, especially shorty/shawty, and possibly a couple bits of needless and unhelpful verbosity. Neither are inherent to Haskell.
Re:Haskell in Production by mbrodersen on Friday October 18, 2019 @09:32AM (#21291190)
> If that's supposed to be the way to write production code in the future, count me out!

Eh? Sorry but the code is really clear to me? Which parts do you find difficult to read?

Re:Haskell in Production by tome on Friday October 18, 2019 @02:28AM (#21289122)
This is roughly the same structure as the code you’d write in Python flask. There’s nothing unusual about it beyond Haskell’s syntax.