The following post is part of Spoke Proof. Tell your friends.
The always-updated treasure map to Haskell
Many people coming into Haskell are daunted by number of choices they have to make: which package to use, which package manager to use, which language extensions to turn on, which resources to read.
So here are some sensible default choices. I’ve noted wherever the answer is still up in the air. Most things are! Many problems in our world have good, but not great, solutions.
Setting up a Haskell environment on OS X
Use stack. Stack
-
Is a sandbox-style package manager. For each project it creates a hermetic little world filled with the project’s dependencies and the project itself.
-
Sets up a “global” project, which is the default project you work in when you run stack outside a project.
-
By the way, a project is any directory with a
*.cabal
or apackage.yaml
file or any subdirectory thereof. I highly recommend usingpackage.yaml
files, otherwise known as the hpack format. With*.cabal
files you have to type the name of each module separately and you have to maintain per-target dependencies. What a hassle.
-
Also installs GHC (
stack setup
) for you. -
Also maintains your
PATH
. If you runstack exec foo
orstack ghci
, you’re runningfoo
andghci
in the context of your project’s sandbox.
Awooga: OS X users will be tempted to use Homebrew to install Stack but that will compile it from source, which takes a good hour on a desktop and possibly longer on laptops. (I have never been patient enough to find out.) Best to just unzip an official release.
The community
Is the best part of Haskell. The community is incredibly kind and supportive. /r/haskell is a medium-traffic subreddit filled with library announcements, fascinating discussions, questions answered by experts, and much else besides. Try Stack Overflow too.
Learning Haskell
-
What I Wish I Knew When Learning Haskell by Stephen Diehl
-
Write You a Haskell by Stephen Diehl
-
The original paper by Philip Wadler that proposed the Monad typeclass – surprisingly readable
-
Cryptopals – not the worst way to learn Haskell, and you’ll learn modern applied information security to boot (You will probably need Crypto.Cipher.AES128 or Crypto.Cipher.AES.Haskell to complete the first chapter.)
-
Chris Allen’s “How to learn Haskell”, another collection of links. Has perhaps the best advice written about Haskell: Don’t sweat the stuff you don’t understand immediately. Keep moving!
Creating a new package
$ cd ~/workspace
$ stack new hello
See also:
$ stack templates
The pain of compilation
Compiling Haskell is slow. Add this to your global aliases (assuming you use zsh):
alias .fast='--fast --ghc-options="-j +RTS -A1024m -n2m -RTS"'
It will teach GHC to use (1) all your cores and (2) more memory while compiling.
Another useful global alias (assuming you use zsh):
alias .fw='--file-watch'
Usage:
stack build .fast .fw
stack ghci .fast
stack install lens .fast
Another suggestion: rebind ;
to :
in your terminal preferences. When Haskelling I never type semicolon but I sure do type colon all the time.
Editor environment
You can’t go wrong with my Haskell Emacs scratchpad. Emacs and Vim are both pretty good choices. Really you need these things:
-
Syntax highlighting
-
Live parsing and typechecking
-
hlint’s suggestions
-
Autocompletion of horribly long module names
-
Being able to send code to an interactive GHC REPL
-
Restarting the REPL when your
.cabal
file changes -
Being able to go from
f x = x
to
f :: a -> a f x = x
with one keypress.
With the right packages, Emacs and Vim have all these features.
IDEs: hdevtools or Intero
This is an active field of development!
-
hdevtools runs a GHCi process in the background and lets your editor interactively query it for typechecking and code-reloading purposes. Comes with integrations for Emacs, Vim, Atom, and Sublime. This is the one that I use.
-
Intero is an Emacs-specific IDE and a rising star. I have not used this much but people speak highly of it.
HTTP client
Use wreq.
HTTP server
Use warp. It implements WAI. If you’re coming from Python, WAI is Haskell’s WSGI. Or Ruby’s Rack. Or Perl’s PSGI.
HTTP framework
This is an active field of development!
This is more divisive. I like to think of each web framework by what new technologies and abstractions they use. These three have all picked very interesting choices, making the Haskell web framework field very diverse:
-
Snap: Snap uses lenses in a neat way that lets you attach additional information to the request at each middleware layer. I think I’m drastically oversimplying snaplets.
-
Yesod: Yesod has great documentation. It also uses conduits, which is a neat little library for modeling streams (with – and this is the hard part – reasonable memory management and error handling) in Haskell. It uses Template Haskell to remove some of the boilerplate of web programming.
-
Servant: Servant is newer but has a cool higher-kinded routes system where you can declare the type of your entire API with type-level programming.
This isn’t like Python or Ruby’s web framework ecosystem, where everybody has sort of decided to coalesce around a monolithic, invent-the-wheels framework (Django, Rails) with lots of smaller, more modular options (Camping, Sinatra, Flask). Lens, conduits, and type-level programming are all cutting-edge stuff.
Web Sockets
Use jaspervdj/websockets for insecure port-80 Web Sockets; use Taylor Fausak’s wuss to get TLS.
JSON
Use Aeson.
Unicode text
Use Data.Text. It’s built on bytestrings and is fast and supports the bare minimum Unicode slicing and dicing. For more Unicode support, see text-icu.
Binary data
Use Data.ByteString. If you need to represent text, upgrade yourself immediately to text.
Lazy text or bytestrings?
I would say avoid them unless you really know what you’re doing. I say this as somebody who doesn’t know what he’s doing.
Lazy IO?
Lazy IO causes more heartache with resource management and error handling than you would expect. Try pipes or conduit instead, which lets you build out streaming data pipelines without leaking file handles or badly handling IO errors. Unfortunately they’re both a little hard to use.
OpenGL
This is an active field of development!
The most comprehensive and well-organized OpenGL library for Haskell is gl by Edward Kmett. How it works is elegant: it downloads the OpenGL specification into a gl.xml
file and then it produces a Haskell library from that XML file. Code that writes code. Its documentation is poor, however; for a tutorial see the primer on Wright Access. For toy examples, see ekmett/quine. Unfortunately the graphics story for Haskell is not quite all there yet.
Lenses
You’re going to keep hearing about lenses because the lens package has achieved remarkable success in the past couple of years, both in terms of creativity and popularity. This series of blog posts takes the time to explain and derive lenses. Lenses tutorials have the same problem as monad tutorials. The reason lenses and monads exist is long-time Haskellers all noticed the same problem, and a lot of (abstract) thought went into thinking of a solution. The original sin of lenses is functionally updating a complicated data structure. The solution is … complicated.
Some lens tips and tricks:
-
Prisms, getters, setters, traversals, and uppercase-L
Lens
in the lens package all compose with.
It all typechecks and type-inferences. This seems simple but it isn’t. It is one of those inventions, like Isaac Newton’s catflap, that does the magic of rendering the blindingly simple into existence. And that’s the secret genius of the lens package: against all odds, they got all the optics to compose with with.
. (Aside: It is impossible in most other languages as it takes advantage of two unique Haskell features, rank-_n_ polymorphism and typeclasses.) -
If you compose a bunch of lens together, you get back the lowest common denominator on this UML diagram. So composing a setter with anything automatically makes it the result a setter. And you can’t compose a setter with a getter – you need a
Lens
. And aLens
composed with a traversal is always a traversal. And only compositions of isomorphisms will yield an isomoprhism. Against all odds, they got all this UML diagram to work exactly as you think it would. -
99% of lens usage boils down to
bigDataStructure operator (lens1 . lens2 . lens3)
, where operator is one of^.
,^?
, or^..
. -
Stop packing and unpacking your strings into bytestrings and vice versa. Use Data.Text.Lens and Data.ByteString.Lens.
-
Stop calling
toStrict/fromStrict
andtoChunks/fromChunks
to convert between strict and lazy bytestrings (and texts). Use Control.Lens.Iso instead.
Prelude
The default prelude is super annoying because you keep importing tiny minimodules like Data.Monoid
and Data.Maybe
to get their helpers. The base-prelude package does all this for you, but you have to turn off implicit preludes (-XNoImplicitPrelude
).
Pointfree
blunt is a little web app that gives you the pointfree version of any function. Be prepared to encounter headache-inducing oddities like (.) . (.)
or the Applicative
instance for (->) r
.
Searching by types
If Hoogle can’t find it, try Hayoo.
Short functions
A good thing to watch out for is functions in Haskell that last for longer than five lines. These might take the form of long do
blocks, or a mess of let ... in ...
s and where
s. These often signal that the function is doing too much. Whereas in other languages we might resign ourselves to the mess, in Haskell we can do better.
I find writing a clean function f
involves asking myself:
-
Is
f
is the composition of some series of functions?f = foo . bar . baz
is one kind of function composition. But so isf = foo >>= bar >>= baz
(and its categorical cousinf = foo >=> bar >=> baz
). -
Is
f
a map over some structure? If I’m taking a list and producing a list, I usually reach formap
andfilter
. -
If
f
folding a big structure into a smaller structure, which aggregates or summarizes the information in the big structure? If I’m taking a list and producing a single value, I usually reach forfoldr
andfilter
.
Horizon
Upcoming GHC developments we should be excited about:
Great Haskell blogs
-
Haskell for all by Gabriel Gonzalez
-
Neighborhood of Infinity by Dan Piponi
-
Inside 736-131 by Edward Z. Yang
-
Simon Peyton Jones – don’t be put off by the academic paper format, as spj is a highly capable technical writer
Parametricity a.k.a. theorems for free
Using types and typeclasses to generate and prove theorems about a function’s invariants. This is like if all your life you carried around this intuition about how something works and then one day someone came along and validated all of it with mathematics and good writing.
-
Parametricity: Money for Nothing by Bartosz Milewski
-
Parametricity Tutorial (Part 1) by Edsko de Vries
-
Theorems for free! by Philip Wadler
Opting into strictness
Confused about seq
and weak-head normal form? Read Roman Cheplyaka’s blog post on forcing lists.
Fiber
The older you get, the more you’ll appreciate a moderate amount of fiber in your daily diet.
Monospace font
Try Ubuntu Mono!
Updates to this document
-
2015 Nov 30: the initial draft was published after a rousing discussion in my friends and I’s #haskell Slack channel.
-
2016 Jan 3: added Web Sockets mention after a fun day with Slack’s real-time messaging API.
-
2016 Aug 18: hdevtools and intero mentioned. Typos fixed.