Live data from Hacker News

Haskell in Production

felixmulder.com

201–210 of 242 posts

Re: Haskell in Production

#201
post #200

Earlier quoted context omitted.

Not really. You can mix them in Haskell too. Think of F# as Haskell except you are always working in the IO monad. Haskell doesn't require a "new way of writing IO code" at all. It just allows you to separate out the IO from the pure in a way that can be enforced by the compiler. But there is nothing preventing you from writing all Haskell code in the IO monad if you were so inclined - which is essentially OCaml/F#.

> Not really. You can mix them in Haskell too. True, but it's not particularly syntactically convenient.

The entire point of monadic (do) syntax in Haskell is to make this convenient. I'm not following you exactly.

Re: Haskell in Production

#202

Earlier quoted context omitted.

I think so. https://insights.stackoverflow.com/survey/2019#technology

That doesn't speak to Haskell. You can say that's because there's not a lot of Haskell and that's likely at least partly true. But the difficulty hiring for a position depends on the number of people qualified and the number of other roles competing for those people. The fact that both of those numbers are smaller for Haskell than (say) Java doesn't tell us whether it'll be easier to hire for Haskell or Java.

True. Lets check the numbers. 90,000 developers took the survey.

Java: 41.1% 36990 developers

JavaScript: 67.8% 61020 developers

Haskell: 0% 0 developers

Jobs:

Java: 73,447 jobs

JavaScript: 59,647 jobs

Haskell: 492 jobs

https://www.indeed.com

Given the numbers, as a hiring manager, I will never ever suggest to any company to try to use Haskell or hire Haskell devs. I know many developers who use it though. They sucessful with what they are doing, turning business problems into Haskell problems and solving those. Sometimes patch the compiler, sometimes write a completely new one. As a tech leader I do not want to have these problems, even if I could hire enough people for projects (which I can't). I always like to read blogs about what is going on though. It satisfies my scientific curiosity but that is it.

Re: Haskell in Production

#203

Earlier quoted context omitted.

I've worked in a pretty wide range of languages. I think I know "unfamiliar" and I can tell it apart from "arcane". OP claims that "this article will emphasize writing easy to grok, maintainable code". The definition of "easy to grok" is not "once you've bought into the entire mindset, this will be obvious to you".

> I've worked in a pretty wide range of languages Which languages are those? If the answer is "N flavours of imperative/OO languages" (like C/C++/Java/C#/Ruby/Javascript) then you really haven't worked in languages different enough for you to truly learn anything new. The rule is simple: if learning a new language is easy, then there isn't much new in the language for you to learn (except a different flavour of synta…

True, most of my work was in imperative/OO languages, though the imperativeness ranged from "global variables for everything" to "No global state, predominantly immutable objects, predominantly single assignment".

But I've also worked in Prolog and SQL, and dabbled in languages like UNITY: https://en.wikipedia.org/wiki/UNITY_(programming_language), so I have some degree of openness to different paradigms.

Re: Haskell in Production

#204

Earlier quoted context omitted.

I've worked in a pretty wide range of languages. I think I know "unfamiliar" and I can tell it apart from "arcane". OP claims that "this article will emphasize writing easy to grok, maintainable code". The definition of "easy to grok" is not "once you've bought into the entire mindset, this will be obvious to you".

"Easy to grok" definitely means "for experienced Haskell programmers". That is who the article is written for. It doesn't matter how many other languages you've used - they are mostly the same as each other and Haskell is really quite different. Your lack of familiarity is not evidence of a defect.

> "Easy to grok" definitely means "for experienced Haskell programmers"

Which is pretty much the definition of "arcane": "known to a small circle of initiates"

Re: Haskell in Production

#205

Earlier quoted context omitted.

It's always good to see examples of how a language is actually used, rather than just assertions of its superiority. That said, if Haskell programmers truly consider this a superior and readable way to write code would tend to reinforce my preconception of them as an insular community elevating arcane jargon to a virtue (not unlike the APL programmers of yore).

> reinforce my preconception of them as an insular community elevating arcane jargon to a virtue I highly recommend not assuming that all "Haskell programmers" agree on what is "superior and readable" code. I also recommend trying to explain "arcane jargon" such as "inheritance", "encapsulation", "method invocation", "recursion", "dependency injection" etc. to people who are not already familiar with such jargon. The…

Let's compare how Wikipedia starts the definition of a "monad":

"a monad [...] is an endofunctor (a functor mapping a category to itself), together with two natural transformations required to fulfill certain coherence conditions."

vs. "encapsulation":

"Encapsulation [...] is the bundling of data with the methods that operate on that data, or the restricting of direct access to some of an object's components."

Are you seriously going to argue that those concepts are equally arcane to somebody not familiar with the underlying paradigm?

Re: Haskell in Production

#206

Earlier quoted context omitted.

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 "parse…

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`…

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

#207
post #187

Earlier quoted context omitted.

Pattern matching for one. I can prove that 3 cases won’t be met but I have to ‘fill in’ them anyway. ADTs with non-Maybe fields. I can prove that all is fine if this ‘slot’ isn’t filled in. Trying to pass an opaque reference down a function call chain. There’s 3.

Sure, thanks, I know where Haskell's type system will ask you to try again if you haven't provided all the information it wants. I'm asking for examples where it genuinely wasn't sensible to change your code to match what the compiler wants. > Pattern matching for one. I can prove that 3 cases won’t be met but I have to ‘fill in’ them anyway. This is a funny one because, no, GHC will not ask you to fill them in! You…

> Pattern matching for one. I can prove that 3 cases won’t be met but I have to ‘fill in’ them anyway.

>> This is a funny one because, no, GHC will not ask you to fill them in! You have to turn on a warning for it to complain. The fact that the warning is not on by default is one of my pet peeves with GHC!

Okay, so let's do the inverse then. I've got a pattern matched case that the type prover proves will never occur (so it throws type error) but I want it to occur.

The answer I know is obvious: I have to add it to the type union. But it should be obvious at this point that the moves I am making are not driven by the outcome I want but by the rules of the type checker. At some point you have to say, Why am I playing these games? Do they really yield tangible, business-facing value?

> ADTs with non-Maybe fields. I can prove that all is fine if this ‘slot’ isn’t filled in.

>>Another funny one, because you can just use `undefined` or `error` and GHC won't complain! Personally I'd probably prefer that it did.

But I don't want an error. I can prove that the absence of the field is OK/not-an-error.

If you say then make it a Maybe, I will tell you sorry I don't have the time to update my entire code-base to contend w/ this novelty to the type checker (I say to the type checker, but this is never a novelty to me and my dynamic code).

> Trying to pass an opaque reference down a function call chain.

>> I don't even know what you mean by that.

my value --(flows at runtime through)--> [some framework, say a web framework code to a, say, a Label that has no idea about my value's type domain] --(flows through pixels to)--> user's eyes

Re: Haskell in Production

#208

Earlier quoted context omitted.

> 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…

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.

Knowing you can >>= doesn't mean you know what something does/what it's for though.

Re: Haskell in Production

#209

Earlier quoted context omitted.

Imagine that Collection had a static method `empty` that created an empty collection of the appropriate type depending on the type you are assigning it to, e.g. `List list = Collection.empty();` would create a list, `Set set = Collection.empty();` would create a set, and so on. This would be fairly similar to how things work in Haskell.

If you know you’re creating a List (it’s there on the LHS) why not write List.empty()?

Here's how it works in Rust. You can imagine this working in Java with reified generics: https://gist.github.com/rust-play/214adf5bd15b18ec2d5c63d97f....

Re: Haskell in Production

#210

Earlier quoted context omitted.

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`…

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,…

1) I'm guessing that the point of confusion is 'does nothing - it's redundant'.

This 'do block' is combining multiple ScottyMs together into one ScottyM. The 'Monad' interface means that ScottM tells you how to combine them together. You could write this in Java as

interface ScottM { ScottM plusRoute(ScottM next) }

get("/", ... ) .plusRoute(get("/:short", ...)) .plusRoute(...)

The difference is that there's lots of library functions which can work on a Monad, but you'll have to write/import all of the utility methods to combine your custom RequestHandler interface.

3)

> How is that request passed into "app"?

"app" doesn't execute handle the request, it is a factory method returning a request-handler of type 'ScottM'. You hook in the 'app' to the webserver on line 94:

  scotty 3000 (app rConn)
You might be getting confused by the "R.Connection" argument; that's the connection to the database, not the HTTP request.

> How is it passed into the "get"?

scotty will apply the "get" to the HTTP request encapsulated as an IO monad. I'm not sure what the internals of 'scotty' are like, but you're basically calling 'ScottM.handle(IOStream)'. 'get' is a 'ScottM' request handler which you combined with the other route handler.

> How is it passed to "param"?

"param" returns "ActionM", which is basically a "Consumer". The rest of the lines here are also "ActionM" which get combined together. The 'get' will in effect call "handle(IOStream)".

Really understanding the niceties of this would require playing around with IO in haskell for a bit. The 'do' syntax is somewhat incomprehensible when you first see it because it is syntactic sugar for a pattern which is used in other languages, but which they don't name. You might have more success learning what it's doing by getting rid of the syntactic sugar and renaming (>>) and (>>=) to more familiar stuff from Java. Maybe it would be best to try it out using Java's CompletableFuture or Stream.

https://en.wikibooks.org/wiki/Haskell/do_notation

Post reply on HN