Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Why I Love Haskell: An Example (thenewsh.blogspot.com)
139 points by apaprocki on April 7, 2015 | hide | past | favorite | 47 comments


Providing type signatures on all top-level functions would've been nicer for teaching purposes


Absolutely. One of the nice things about Haskell and its type system in general is being able to look at a function's type and induce roughly what it does. Or, vice-versa, the ability to find pieces of functionality on hoogle by giving a reasonable type signature for your desired code.

Skipping out on that visibility when showing how Haskell is expressive seems like a missed opportunity.


Is hoogle a special search engine for Haskell code or was that an unintentional typo?


It is a special search engine for Haskell libraries. For example, if I want the `map` function but don't know what it's called (or what library it's in) I can search for its type signature, which must be something like `[a] -> (a -> b) -> [b]`. Hoogle finds exactly what I'm looking for: https://www.haskell.org/hoogle/?hoogle=%5Ba%5D+-%3E+%28a+-%3...

Note that this is true even though I reversed the argument order. It does fuzzy-matching of some sort. It will also help if you know the name of the function, since it searches those, too.


Yes, it's a special search engine: https://www.haskell.org/hoogle/

You don't search for words in the documentation etc., but enter the type of the function you want. This often works pretty well.


FPComplete's Hoogle is a bit more complete: https://www.fpcomplete.com/hoogle


It's good overall but sometimes the ranking is weird. For example, if you search for "ByteString", what you'd expect is only the #3 hit.

For beginners who are likely to be searching for core libraries, the other Hoogle might be more useful.



It's an idea that comes from Smalltalk, where for the longest time they've had a way to search for object methods given an input and an output, and it would search which object method did that.

So you can give it "blah" and "Blah" and it would find the method "capitalize" for instance.

Hoogle is like that but for Haskell, and instead of giving inputs and outputs you give it a few types and it looks for them in the function signatures.


Took 10 mins to hack a silly, inefficient version.

https://play.golang.org/p/UPlzWR5OCO

Gives the same result as https://www.ietf.org/mail-archive/web/tls/current/msg03416.h... SHA256 test vector.

Looks easier to understand, to me...


It actually looked much more difficult to understand to me because golang just really has no structure.

Anyways, it probably is simpler, because it doesn't solve the same problem that the Haskell code solves. The Haskell code allows you to generate some bytes from the infinite stream even if you don't yet know how many you need; your go version must know how many you need before you start.

In order to do the same thing in go you're going to need to use an iterator or a goroutine + channel. Try doing that as cleanly as the Haskell version.


This can be done very easily using an unbounded io.Reader instead of channels or iterators.

Here's a slightly modified version of bluefox's code where the prf function returns an unbounded io.Reader: https://play.golang.org/p/ZAj8q4eXEi

And here's a version that's modified a bit more, but still essentially the same, to trade LOC for matching the spec very cleanly: https://play.golang.org/p/Rpy0yIwVN1


Just to be clear, a Pipe counts as a channel for me; like I said, it requires a goroutine. Don't get me wrong, this is definitely the "right" go implementation, and what GHC does internally with thunks is way worse than goroutines.

The point is it no longer looks so superior to the Haskell version, especially since there were many LOC in the haskell version just defining the Key datatype which go never does.


I don't see any kind of error handling, but if I understand correctly, in some cases in Go it is not necessary to check for errors directly (an errorneous output stream would do-nothing on write, for example). Do you think your versions are fault-tolerant or is there anything you should add to gracefully handle errors?


A Hash's Write method can't return an errors.

Writing and Reading to a pipe only errors if the pipe has been closed. We return an io.Reader, instead of an io.ReadCloser, so consumers can't close the Read side. Internally, the Write side is never closed either. So, in practice, Reading and Writing also won't ever error.


But is yours easier to reason about?

There is no doubt a steep learning curve with Haskell and FP in general. You may be thinking: what is all this <$> <*> and $ nonsense! However once learned, you can look at the Haskell code and it is more clear precisely what it is doing (and what it can't possibly do).

I think the article undersells Haskell. Haskell gives you code purity. Purity means you can reason about a function. A function that takes in an Int and returns an Int won't read data from your disk. It won't call a web service to get the answer. It won't update the counter int on your class and then one day cause it to overflow, causing another class that reads the counter int to throw an exception. This makes maintaining code a hell of a lot easier and more pleasant.


Why would this be difficult in other languages, especially other modern languages? I wish the author expanded on it as I don't see anything special about the use of Haskell here.


Did he not?

> Haskell provided a very light-weight syntax.

> Haskell allows partial-application of functions.

> Haskell allows definitions of unbounded data structures...

> Higher-order functions like "iterate" and "map"...

> Monads allowed me to avoid having to explicitly track side effects ... [also] purity and strong type checking.

> Libraries of higher order functions for monads allowed me to limit the syntactic cost of using monads.


That just tells me he did it the Haskell way. That doesn't answer the question of why it would be more difficult in other (modern) languages.

If you're going to make an audacious claim then we need to see evidence to support that claim. The author didn't do this. All the author did was show us a Haskell implementation.


No, but he did say "beware, herein lies advocacy." Which is a tongue-in-cheek version of saying "ok, I know, I didn't do my due dilligence, but it's my blog and I love Haskell and I'm excited about this one thing I just built."

Not everything is a paper in Nature. I understand your point but he's honest about it just being a propaganda piece.

And, frankly, what's wrong with that?

Thanks to the author for taking the time to share.


>And, frankly, what's wrong with that?

That it doesn't solve OUR problem, which is "help us chose if Haskell if better", even though it pretends to?


I don't see how it doesn't help. It might not help as much as could be asked, but it's a cute example of "real world" Haskell use and he described the parts of it he rather liked.


Here's a follow up post from a different author, that continues on this subject, and also explains some of the benefits of the haskell approach: http://nikita-volkov.github.io/a-taste-of-state-parsers-are-...


None of these are both a) special to Haskell and b) necessary to solving this problem in a clean way. So no, he did not. It's also worth pointing out that the last point contradicts the first.


I don't think he claimed (a) or (b). Instead, he claimed that Haskell has all of these features together and that the culminating result is a pleasant implementation of a real-world problem.

Finally, the last point does not contradict the first. You can have lightweight syntax and use it to express heavyweight ideas. Then you can have libraries which help to alleviate that weight. This is a non-trivial task—it involves the abstraction power of your language and, in the case, the logical power of your type language.


I salute you if you understood anything in "The Problem" section.


This is my problem with everything I encounter when trying to learn about Haskell. I find almost everything I come across to be completely unapproachable. If I cant understand the problem you're solving in the blog post then the solution makes even less sense. I don't say this as a criticism of this author at all. It's just something I've noticed with Haskell.


I'm glad I'm not the only one who feels that way. I find that with many articles on functional languages, which leaves me wondering if they attract a certain type of person, or if they're just not well suited to the problems I work on.

Is there anything good on doing web development in a functional style? I keep hearing about Om and Clojurescript in relation to React, but I have no idea where to start.



If you count Lisp as functional[0] it has a pretty big web presence, both Common and Scheme.

Functional languages reward (require?) a different kind of problem domain analysis than imperative languages do, and one of the things they are least good at is "I want to track the state of a bunch of discrete things that share similarities in structure", ie, 90% of Web programming. (But then again maybe that's only 90% of web programming because OO was the fad-of-the-day when web programming took off.)

There's the old adage that data structures tell you a lot more than flowcharts; languages like Haskell and ML kind of turn that on its head. Rather than using functions to apply and track changes of state to abstracted chunks of memory, you apply and track changes of state by composing the functions with each other. This is great for some problem domains (eg, I think there's a reason that so much prototyping and code analysis is done in Haskell and ML) and less great for others (interfacing with a table-based database always felt kludgey to me, for instance).

I do think they attract a certain type of person, namely the kind of person who prefers debugging on paper to debugging in memory. Haskell may well have a debugger, but I've never used it because I always do a static debug, usually with a physical code printout. Then again I'm also a crotchety geezer.

TL;DR: many functional languages aren't great for the kinds of problems a lot of developers today are trying to solve, but the process of refactoring those problems in a way that does make functional languages useful is often a Good Thing for a developer to do.

[0] I would argue it's not "functional" except in an accidental sense; it's a "symbolic" language that happens to have first-class functions. Lisp is mostly useful for writing more Lisp (but note "mostly"; I'm a confirmed Lisp Weenie and I find myself very productive in it).


This website is written in a Lisp dialect.


I'm aware of that, so clearly its possible, I just have no real idea how I'd approach that myself.


The problem statement is basically copied verbatim from RFC 5246 sections 5 and 6.3.

The author picked a cryptographic function from a rather important and widely deployed real-world internet protocol (TLS 1.2), but of course since the author is writing about Haskell readers assume it must be some esoteric academic nonsense that undoubtedly involves category theory, whatever that is.


I didn't say anything about "esoteric academic nonsense." Just because the subject matter is a part of something that is very commonly used does not mean it is outside the reach of many very competent people.


Ehh sorry for the hyperbole, was feeling a bit grumpy that day :-)


Its not difficult. The author has a stream of data (random bytes for crypto keys) which needs to be consumed in different bits of the program at different times. The traditional ways are either a global variable holding the current state of the generator or else re-assigning that state to one or more variables in a complicated and error-prone way.


I like Haskell because of some of the related tools.

- HLint, a very helpful linter for ideomatic Haskell

- QuickCheck, Fuzz-testing function's properties

- hpc, Pretty code coverage


I find the Haskell tooling ecosystem surprisingly terrible, given how rich the information content of the code is. There's virtually no equivalent of most functions from e.g. Intellij for Haskell that I know of (although I haven't tried FPComplete's tools yet and hear good things).

The libraries you mentioned though are indeed all really fantastic, and after learning how to use them you'll miss them dearly when they're unavailable.


There are all sorts of tools, even for refactoring. Maybe not to the degree of Java, no. Although, haskell code tends to have less boilerplate, so there is less toolig for manipulating boilerplate. (Not to say there are other tools that could be improved). But the situation is far from dire.

-- Vim:

haskellmode-vim for show type and insert type, among other things.

ghcmod-vim for HLint and HCheck, also used by Syntastic and NeoComplCache.

neco-ghc uses ghcmod-vim for nifty Haskell completion, powered by neocomplcache.

Syntastic automatic syntax checking for vim.

--Emacs:

structured-haskell-mode: https://github.com/chrisdone/structured-haskell-mode

haskell-emacs: http://chrisdone.com/posts/haskell-emacs


Then your Haskell expert leaves and then you learn why I hate Haskell(or insert any fringe programming language here).


Learning Haskell isn't beyond any programmers though, and is likely to pay off long-term. I agree that other fringe languages might have less payoff though - Erlang/elixir, Clojure, F#/OCaml, Idris/Coq/Agda (although who would write production code in these?) are all more likely to impart fundamental understandings than e.g. Coffeescript, Wisp, etc.


Learning kung fu or the violin isn't beyond most people either, but I'd rather not have that be the prerequisite for being able to be productive on my team.

Most companies don't prioritize paying a potentially highly compensated worker to learn an obscure language when the job can just as effectively be solved using standard skills and languages that are much easier to acquire(hire).

Also, despite the passionate defence that many functional-first language advocates give, I have never seen any conclusive evidence that these languages, in general, produce better results than the standard suspects.


Having a team member create production code in a language nobody else on the team understands is a risky decision. That applies for anything, software, systems, infrastructure... if one developer is allowed to sit on something, what happens when the dev leaves? Or dies? And the thing he or she worked on had a non-trivial learning curve?

Choosing something like Haskell or anything else niche should be a group decision. Even when it comes to prototyping! "Guys, I'm going to prototype this .NET code in F#. Who wants to join?", instead of a developer sitting in a corner applicating his functors while others around him do something arguably simpler. It's incredibly short-sighted!

This is not aimed at you though, since I'm not sure if this was your case, I'm only guessing based on your post.


This. We're still waiting for Haskell's killer app.


Can you give some examples of killer apps in other languages, so I know what sort of example you're looking for?


Why I Love My Left Arrow

When pressed in combination with the alt button, it can navigate back to the previous page I was viewing. But not when someone captures onkeypress and cancels it.


That's because you didn't use the IO monad.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: