FAQ

From HaskellWiki
Revision as of 03:28, 13 April 2024 by Atravers (talk | contribs)
Jump to navigation Jump to search

This FAQ is based on actual frequently-asked questions from #haskell IRC. The goal is simply to collect and edit some common answers. Beginner questions are still welcome on IRC, as always.

This is a wiki, so please edit the text with any improvements you have. And feel free to add new questions, if they are frequently asked.

See also

The real world

Should I learn Haskell?

That depends on your goals. In general, Haskellers will tell you that you should learn Haskell. :)

Learning Haskell is fun. It will expand your mind and make you a better programmer in other languages. These are the immediate benefits.

Haskell is also a great tool for solving real-world problems, but it can take many months of study to get to that point.

Is Haskell hard to learn?

Any competent programmer can learn Haskell, but it will take more time and motivation than you may expect.

Haskell requires learning a new way to think, not just new syntax for old concepts. This can be incredibly frustrating, as simple tasks seem impossibly difficult.

Those with no prior programming experience may actually have an easier time learning Haskell, because they have less to un-learn.

How can I get started with Haskell right now?

Check out Try Haskell.

Also: FP Complete's free online IDE


What should I read for learning Haskell?

The most popular resources are Learn You a Haskell and Real World Haskell. Each is available online for free, or can be purchased in hardcopy.

Many other tutorials, books, and other resources are available.

There's also the School of Haskell which has a set of free online tutorials with runnable examples.

How can I get help with learning Haskell?

Your options include:

Will Haskell get me a job?

There are plenty of companies using Haskell, but it's still a tiny number compared to the software industry as a whole.

There are also many companies which do not use Haskell, but prefer to hire people who know Haskell. It indicates that you learned something hard and obscure just for fun, which employers take as a sign of intelligence.

Is Haskell similar to Language X?

Probably not. It's best if you approach Haskell with a clean slate. Most analogies to another language will break down somewhere, often in a subtle and misleading way. If you first learn the Haskell concepts for what they are, you can then draw useful connections to other languages.

What's the relationship between Haskell and GHC?

Haskell is not a piece of software; it is a specification for a standardized programming language. The latest version of the spec is the Haskell 2010 Report.

GHC is the Glorious Glasgow Haskell Compiler. It is by far the most popular and "production-ready" implementation of the standard Haskell language. It also implements many extension features that go above and beyond standard Haskell. Many programs use these features and so aren't "written in Haskell" in the strictest sense.

You can use the term "Haskell" to refer to the standard language, and "GHC Haskell" when including GHC extensions.

Besides GHC, several other implementations of Haskell are available. Each one provides its own extensions, some of which don't exist in GHC.

What is the Haskell Platform?

The Haskell Platform is a copy of GHC bundled with a "blessed" set of useful libraries. It is the easiest way to get started with Haskell. It's not essential to start with the Platform, because you can install the same libraries as needed.

What is Haskell Prime (Haskell')?

Haskell Prime is a process which produces new versions of the Haskell language spec. It does not refer to a particular present or future version of Haskell.

My textbook uses Haskell 98. Is it very different from Haskell 2010?

No. Haskell 2010 is a very conservative change to Haskell 98. It fixes small syntactic flaws, and standardizes several well-behaved extensions which GHC has supported for years.

The standardization process is very slow because standardizing a flawed language can be a costly mistake. Extensions are accepted only once they are considered mature and well-understood.

How do I get libraries for Haskell?

You can find libraries on Hackage, and install them with cabal-install.

Is Haskell compiled?

Usually. GHC, the most popular Haskell implementation, has an optimizing ahead-of-time native-code compiler, as well as a bytecode compiler and interpreter for interactive use.

Haskell itself is not a "compiled language" because nothing in the Haskell spec requires implementations to be compilers.

Does Haskell have an interpreter?

Yes, but maybe you instead mean "Is there a program where I can type Haskell code and see it run immediately?". GHCi provides such a "read-evaluate-print loop".


Which project can I join?

See Haskell projects needing help.

Paradigms

Is learning Haskell the best way to learn functional programming?

Not necessarily! Haskell is not a typical functional language. It can be overwhelming to learn the basic concepts of functional programming alongside static types, algebraic data, laziness, type classes, first-class IO, etc. For an introduction to FP by itself you might want to learn Scheme, or play with the FP features in your current favorite language.

That said, many people choose Haskell as an introduction to FP and have success with that approach. Haskell has an extremely active community of people teaching, doing research, writing libraries, etc. Haskell is where interesting things happen in the FP space, so it's an exciting place to jump in.

I heard Haskell is pure functional. Does that mean it doesn't have mutable state?

No; see IORef for a simple example. A more sophisticated example is software transactional memory, which provides concurrent state more sophisticated than you'll find in most other imperative languages.

I heard Haskell is pure functional. Does that mean I can't do imperative / OOP / aspect-oriented / logic programming in Haskell?

No, "pure functional" has a specific technical meaning. It doesn't mean that functional is the only supported paradigm.

Paradigms describe the techniques used in a particular program. For example, the Linux kernel is written in C, with pervasive use of functional, object-oriented, and aspect-oriented programming. The most we can say about a language is that it encourages or discourages a particular paradigm. Haskell is very flexible and can comfortably accommodate most paradigms, even when there is no built-in support.

Wait, is Haskell imperative or is it functional?

Both - and it's also referentially transparent. In Haskell, functions are first class, and so are imperative actions.

There is no reason to consider "imperative language" and "functional language" as mutually exclusive. It's only a historical accident that a few of the most popular imperative languages are unusually bad at functional programming. Functional imperative programming is extremely powerful and is supported by many languages.

Math

Was Haskell designed by mathematicians?

Haskell was designed by people studying programming language design. Perhaps programmers would consider them to be mathematicians, while mathematicians would consider them to be programmers.

Designing a programming language is a hard thing to do. There are many non-obvious tradeoffs, and many lessons to be learned from past failures and successes. Yet many of today's most popular languages were designed by people who hadn't done their homework.

Haskell was designed by people who knew what they were doing. It's not perfect, but the contrast to an amateur's design is striking.

Do I need to know advanced math in order to use Haskell?

No. Certain concepts in Haskell are named after concepts in advanced math. But other languages also appropriate math terminology: consider "singleton", not to mention "function" and "variable". The way these programming concepts relate to actual mathematics is not necessarily important or relevant.

In addition, some people write articles about advanced math, using Haskell syntax as their notation. These articles are interesting, but the connection to everyday programming work is usually remote.

Knowing advanced math will enrich your experience using Haskell, but is by no means a prerequisite.

Types

Doesn't a static type system just make it harder to write programs?

Yes. In particular, it makes it much harder to write incorrect programs.

The tradeoff is that correct programs also become somewhat harder to write. In Haskell, features like type inference mitigate this burden to a large extent.

How do I make a list with elements of different types?

Are you sure that's what you want? Consider instead creating a single data type to encompass the alternatives:

data Identifier
    = ByNumber Int
    | ByName   String

doStuff :: [Identifier] -> Whatever

In many dynamically-typed languages you aren't allowed to create "variant types" like this. The type system itself is used as a single ad-hoc global variant type. Keep this in mind if you're translating designs from a dynamically-typed language to Haskell.

No really, how do I make a list of elements of different types?

Well, you can't avoid putting all your values into one type. But sometimes the "variant type" approach above is too restrictive. Maybe you need to let other people add to the set of allowed types, the way Control.Exception allows users to define new exception types.

You can use an existential type, possibly with a type class. Or you can use Data.Dynamic.

I'm making an RPG. Should I define a type for each kind of monster, and a type class for them?

Probably not. Some languages require a new type for each new behavior. In Haskell, behaviors are functions or IO actions, which are first-class values. So you can store behaviors in an ordinary data type:

data MonsterOps = MonsterOps
    { new    :: Monster
    , move   :: Monster -> Monster
    , attack :: Monster -> Player -> Player }

data Monster = Monster
    { position  :: (Int, Int)
    , hitpoints :: Double }

beholder :: MonsterOps
beholder = MonsterOps new move attack where
    new = Monster (0,0) 9000
    move   self = ...
    attack self player = ...

This approach is especially nice if you want to generate or transform behaviors on the fly. See the article "Haskell Antipattern: Existential Typeclass" for a longer discussion.

What's the difference between Integer and Int?

Integer can represent arbitrarily large integers, up to using all of the storage on your machine.

Int can only represent integers in a finite range. The language standard only guarantees a range of -229 to (229 - 1). Most implementations will provide a full machine-size signed integer, i.e. 32 or 64 bits.

Operations on Int can be much faster than operations on Integer, but overflow and underflow can cause weird bugs. Using Int in an initial design could be considered premature optimization. Unfortunately, many standard library functions (e.g. length, take) use Int. There are also generic variants of those.

How do I convert type A to type B?

This is just another way of asking for a function of type A -> B. For example, you can convert Double to Int with round, ceiling, or floor. Haskell does not privilege one of these as the conversion.

Does Haskell have type casts?

The word "cast" can mean a lot of different things.

  • You want to convert a value from one type to another, preserving some idea of what it means. For example, you might convert an Int to a Double which represents the same integer. In this case you'd just use a function of type Int -> Double, such as fromIntegral. Haskell doesn't provide special rules or syntax for these functions. See also the previous question.

  • You want to pass a value of more specific type to a function expecting a less specific type. There's no syntax for this in Haskell; you just do it. For example you can pass x :: Int to show :: (Show a) => a -> String, which automatically specializes the type of show to Int -> String. Note that Haskell does not have subtyping, so this only happens in the context of instantiating type variables.

  • You want to use a value of less specific type under the assumption of a more specific type, with a checkable runtime error if they do not match. This is rarely the right way to do things in Haskell, and probably indicates a conceptual / design problem instead. If you really do need such a cast, you can use cast from Data.Typeable. In this case the "checkable runtime error" is cast returning Nothing. Note that Haskell does not have subtyping, so this only happens in the context of instantiating type variables.

  • You want to use a value of less specific type under the assumption of a more specific type, and if the assumption is incorrect, the program is allowed to segfault / silently corrupt data / give the attacker a root shell / send illicit photos to your boss. Also known as a "reinterpret cast". GHC Haskell has a way to do this, but I dare not speak its name. It's so dangerous and so unlikely to be what you want that it has no place in a general FAQ. You can ask on IRC or read the docs if you have the right kind of morbid curiosity.

How do I convert from one numeric type to another?

Probably using one of these:

fromIntegral :: (Integral a, Num b       ) => a -> b
realToFrac   :: (Real a,     Fractional b) => a -> b

fromIntegral converts to a wider range of types, but realToFrac converts from types which aren't integers.

How do I convert Maybe Int to Int?

Use pattern-matching. If mx :: Maybe Int:

case mx of
    Just x  -> ...
    Nothing -> ...

This forces you to consider the Nothing case, and is the main advantage of Maybe, compared to adding a null value to every type.

See also the functions maybe and fromMaybe in the module Data.Maybe.

Do not use fromJust, because passing Nothing will crash your program with a supremely unhelpful error message. Even when you want to assume the value is not Nothing, you can provide a better error message:

let x = fromMaybe (error "custom error message") mx in ...

If you pattern-match without a Nothing case:

let Just x = mx in ...

you'll at least get a line number in the error message:

*** Exception: foo.hs:2:9-24: Irrefutable pattern failed for pattern Data.Maybe.Just x

How do I convert between String (or Text) and ByteString?

String represents a sequence of Unicode characters. ByteString represents a sequence of bytes. There are many different, incompatible ways to represent Unicode characters as bytes. See this article if you're fuzzy on the character / byte distinction.

The module Data.Text.Encoding from the text package provides functions for common Unicode encodings. For more obscure / legacy encodings, see the text-icu package.

How do I catch the error thrown by read on a parse failure?

Don't. Instead use

import Text.Read (readMaybe)
readMaybe :: Read a => String -> Maybe a

which returns a Nothing in the case of parse failure.

What's the difference between type, data, and newtype?

type introduces a synonym, which is fully interchangeable with the original type:

type Foo = Int

main = print ((2 :: Int) + (3 :: Foo))

So it provides convenience and documentation, but no additional type checking.

data is used to define new data types, distinct from any existing type.

newtype can mostly be understood as a restricted form of data. You can use newtype when you have exactly one constructor with exactly one field. In those cases, newtype can give better performance than data.

There is, however, a subtle difference between data and newtype semantics, which is why the newtype optimization is not applied automatically.

Making it work

How can I find type errors?

There's no silver bullet, but here are a few useful techniques:

  • Comment out type signatures and see what GHC infers, using :t in GHCi.
  • Add more type signatures, for example inside let. This makes your assumptions clearer, so GHC's error message may better explain how your assumptions are inconsistent.
  • Replace some subexpressions with undefined, which can assume any type. In more recent versions of GHC, you should insert a "type hole", written _ (a single underscore) instead of undefined for this purpose. GHC's error message will then indicate the type it's expecting for the expression in the hole.

How can I find bugs that occur at runtime?

With pure functions, correctness is a matter of getting the right output for a given input. If one function gives incorrect results, you test the functions it calls, and so on until the bad code is located. You can perform these tests directly in GHCi, or with the help of a tool like QuickCheck.

You can trace evaluation using Debug.Trace. You'll get a printout when the expression is evaluated. Due to lazy evaluation, this might be at an unexpected time. But this property is useful when debugging problems related to excessive laziness.

GHCi also implements a "simple imperative-style debugger".

Haskell is a natural fit for novel "declarative debugging" tools but to our knowledge, no such tool is production-ready.

Why do I get an "undefined symbol" linker error when compiling?

If you're using GHC 6, you should pass --make so that GHC will automatically link the appropriate Haskell libraries.

How can I get a stack backtrace when my program throws an exception?

The standard stack in GHC Haskell doesn't represent nested function calls. The more informative stack is the profiling cost-center stack, which only exists if your code is built for profiling.

With GHC 7 you can do something like this:

$ ghc -fforce-recomp -prof -auto-all -rtsopts foo.hs

For GHC 6 you should leave off -rtsopts, and you'll probably want --make.

You can then run your program with the -xc RTS option`:

$ ./foo +RTS -xc

How can I do automated unit testing?

See the testing chapter in Real World Haskell.

How can I find and fix performance problems?

See the profiling and optimization chapter in Real World Haskell.

Modules

How do I deal with name clashes between modules?

You can disambiguate by prefixing a module name:

import Data.List
import Data.Map

f = Data.List.lookup 7
g = Data.Map.lookup  7

The import syntax gives you additional control:

  • With import qualified Foo the names from Foo can only be used qualified, and won't clash with unqualified names.
  • With import Foo as M you'd write M.x instead of Foo.x.

You can combine these two features. A more common way to write the above example is:

import qualified Data.Map as M

f = lookup   7  -- unqualified, from Prelude
g = M.lookup 7

In general, most combinations of import features are allowed. You can combine as and qualified with import and hiding lists. You can import two modules as the same name, or one module as two names, with different import and hiding lists, qualified or unqualified, etc.

How do I control the Prelude import?

Haskell modules implicitly import Prelude, unless an explicit import is given. So you can write

import Prelude as P hiding (length, head)

How do I qualify the name of an infix operator?

You prefix the module name, as usual:

x = 2 + 3
y = 2 Prelude.+ 3

f = (+) 7
g = (Prelude.+) 7

This looks weird but works fine. The syntax does clash a bit:

xs = [False..True]    -- wrong, parses as qualified name
xs = [False .. True]  -- ok

How do I mention an infix operator in an export / import / hiding list?

The same way as elsewhere: enclose it in parentheses.

import Prelude ( succ, (+), length, (*) )

I listed a data type in my import list but its data constructors aren't in scope. How do I fix it?

You have to import data constructors explicitly:

import Prelude ( Maybe )           -- the type only
import Prelude ( Maybe(Nothing) )  -- type and specific constructor(s)
import Prelude ( Maybe(..) )       -- type and all its constructors

How can I import and re-export a whole module?

module Bar ( module Foo ) where
import Foo

How can I export another module and everything defined in this module?

module Bar ( module Bar, module Foo ) where
import Foo

Input/Output

I heard Haskell is pure functional. Does that mean it can't do IO?

No; IO in Haskell is straightforward.

Do I need to understand monads in order to do IO?

Not really. "Monad" is the name of a generic API that applies to many different types, including the IO type. If you're only thinking about IO, you don't need to worry about how this API generalizes.

See the Introduction to IO.

How do I convert IO Int to Int?

Assuming the type mismatch is occurring in an Haskell definition which already relies on I/O:

g :: IO Int
g = do ...

f x y = do ...
           n = g
           ...
           v <- h n
           ...

then you have two options:

  • the simplest option is to use some extra do notation:
f x y = do ...
           n <- g
           ...
           v <- h n
           ...
  • but occasionally a monadic-binding operator such as (=<<) can also be used:
f x y = do ...
           n = g
           ...
           v <- h =<< n
           ...

How do I convert IO Int to Int inside a pure definition?

You can't; if you could then the definition would stop being pure no matter what its type is. More importantly, if you could do that then so could others! Now imagine you're the one trying to find an error in a library full of pure definitions; an error that only occurs when the library is used in parallel programs. As libraries can depend on other libraries, which can depend on yet more libraries...where would you even begin to look?

So much trouble, and all because someone could convert an IO Int to Int inside a pure definition, one that's supposed to work in parallel...perhaps no-one should be allowed to do that.

Now please read the Introduction to IO.

I have another question...

  • It could be in Stack Overflow's list of questions about I/O in Haskell.

The M-word

See also "What a Monad is not".

I heard Haskell is about monads. I heard that the core feature of Haskell is monads. Is that true?

Absolutely not.

What should I know before trying to understand monads?

Let's look at part of the definition of Monad:

class Monad m where
    (>>=) :: m a -> (a -> m b) -> m b

This uses a lot of features:

  • first-class functions: the second argument to (>>=) is a function
  • type constructors (here m)
  • type class polymorphism
  • type class polymorphism over type constructors (which few other languages have)
  • parametric (not type class) polymorphism, over a and b

Each of these features is more fundamental than the specific idea of monads. If you understand each feature, then Monad is a small example of how they fit together. Functor is a slightly simpler example, and you can start there instead (see Typeclassopedia).

Aren't monads just a hack for handling impure things in a pure language?

No. This is wrong in several ways.

First, Monad isn't special. Monad is an ordinary Haskell type class. You can define it yourself in a few lines of pure Haskell code, so it's definitely not adding magical new capabilities to the language. Besides that, Monad is an API, not an implementation.

(The do syntax is special, but it's only syntactic sugar. There's a straightforward translation to ordinary function calls, lambdas, etc.)

Second, most monads have nothing to do with effects or "impurity". The Monad API is implemented by many different type constructors, including Maybe and []. Lists and Maybe values are straightforward, familiar data values. There's nothing "impure" about them.

Third, IO is not an exception to purity. IO actions are pure, first-class values like any other. You can create, store, and evaluate them without causing side effects. IO actions are just descriptions of IO which could be performed.

In short, Haskell programs are pure-functional programs which compute imperative programs.

It's true that IO implements the Monad API, but that's not fundamental. You could instead use non-overloaded functions like

returnIO :: a -> IO a
bindIO   :: IO a -> (a -> IO b) -> IO b


to glue together IO actions, and it would all work out basically the same. We use the generic Monad API for IO not because we have to, but because it lets us reuse convenient syntax and libraries. Indeed, you can introduce IO without mentioning Monad at all.

I heard monads are like burritos or space suits full of nuclear waste. Is that true?

These analogies are not helpful. See "Abstraction, intuition, and the 'monad tutorial fallacy"'.

I can use monads but I feel like I still don't "get" them. What am I missing?

You're not necessarily missing anything. "Monad" is just the name of a generic API that applies to many different types. The types implementing the Monad API don't have a lot in common.

You might want to read "Typeclassopedia" to see how Monad fits in with other similar APIs.

What's the difference between State s and ST s monads?

State s a is just a wrapper for the function type s -> (a, s): a function that takes an "old state" and returns a "new state" along with its result. You can implement State in a few lines of standard Haskell, without any special help from the compiler.

ST gives you true mutable variables with in-place update. You can't implement it yourself in standard Haskell. In GHC, STRef and IORef will behave the same way at runtime. The difference is the extra compile-time safety checking associated with runST.

Concurrency and parallelism

See also notes on parallel and concurrent programming.

How can I do X without resorting to threads?

That's usually the wrong attitude. Threads are useful for solving problems. The attitude comes from other languages where some combination of the following holds:

  • Per-thread overhead consumes a lot of memory or CPU
  • Thread APIs are cumbersome, sometimes due to lacking first-class functions or IO actions
  • The thread implementation is fundamentally broken, e.g. a global interpreter lock
  • Threads break easily because programs constantly mutate implicitly-shared state

None of these is true in GHC Haskell. Threads have disadvantages and are not always the right tool. But avoiding them at all costs is counterproductive.

What's the difference between concurrency and parallelism?

Briefly: concurrency describes semantics; parallelism describes an implementation property.

Concurrent programs are written with explicit threads of control. Concurrent semantics fit naturally with certain real-world problems, like a network server talking to many simultaneous clients. This is still a nice model for writing a network server, even if you only intend to run it on one CPU core — concurrency without parallelism.

Parallel programs are those which run on multiple CPU cores simultaneously, regardless of how they were implemented.

Concurrency is a popular way to obtain parallel performance, but converting a pure computation to use concurrent semantics is difficult and error-prone. GHC Haskell provides "semi-implicit parallelism" as an alternative. Adding these "annotations" to a program cannot change its behavior.

There's a longer discussion on the GHC blog.

How do par, pseq, and seq relate?

The expression par x y is semantically equivalent to y, but suggests to the runtime system that evaluating x in parallel might be a good idea. Usually x would be a variable referring to a thunk (unevaluated expression) that will later be needed.

Now consider par x (x+y). Evaluating this expression suggests evaluating x in parallel. But before the runtime system can act on that suggestion, we evaluate (x+y), which will evaluate both x and y in sequence. It would be better to work on y for a while, and only demand x later, after perhaps some parallel work has occurred. We can use pseq to force this evaluation order, as in par x (pseq y (x+y)).

The Strategies module provides a nicer interface to these par / pseq tricks.

seq is similar to pseq but provides a weaker guarantee. The details are subtle; suffice to say that if you're controlling evaluation order, you want pseq.

How do I do event-based IO in GHC Haskell? Should I call select, epoll, etc?

No; just do blocking IO from multiple threads, and GHC's runtime system will make these calls for you. GHC Haskell gives you the performance benefits of event-based IO without making you turn your code inside-out.

Threads in GHC are lightweight — both in performance and in the mental effort of using them. You can handle ten thousand concurrent requests at high throughput with a naive "one thread per client" model.

What's the difference between forkIO and forkOS?

It only matters if you're calling into a C library that cares about thread-local state. In that case, forkOS guarantees that the C library will see the same OS thread each time. Any difference beyond that is an implementation detail and subject to change.

How can I wait for a thread to finish and produce a result?

There's a few libraries for this on Hackage, like async, spawn, and threads.

It's not hard to implement this yourself using MVar, though it's harder to get the exception handling right.

IRC

What does lambdabot's "info" command do?

At first, it seems like it just echoes whatever you type:

   <user> ?info foo bar baz
   <lambdabot> foo bar baz

What is actually happening is that it autocorrects to the "undo" command, which desugars do blocks according to the Report's rules. So, a more interesting example might look like this:

   <user> ?info do { foo; x <- bar; baz }
   <lambdabot> foo >> bar >>= \ x -> baz


Error messages and warnings

Not in scope: `catch'

The function "catch" is removed from Prelude, add the line:

import Control.Exception

(Note, that this might lead to an error if you compile the same code with an older GHC.)