Personal tools

FAQ

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
(add questions about concurrency and parallelism)
(more concurrency)
Line 500: Line 500:
 
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.
 
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 [http://blog.johantibell.com/2010/09/final-version-of-our-ghc-io-manager.html ten thousand requests per second] with a naive "one thread per client" model.
+
Threads in GHC are lightweight — both in performance and in the mental effort of using them. You can handle [http://blog.johantibell.com/2010/09/final-version-of-our-ghc-io-manager.html ten thousand concurrent requests] at high throughput with a naive "one thread per client" model.
  +
  +
== What's the difference between <hask>forkIO</hask> and <hask>forkOS</hask>? ==
  +
  +
It only matters if you're calling into a C library that cares about thread-local state. In that case, <hask>forkOS</hask> 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 [http://hackage.haskell.org/package/async <tt>async</tt>], [http://hackage.haskell.org/package/spawn <tt>spawn</tt>], and [http://hackage.haskell.org/package/threads <tt>threads</tt>].
  +
  +
It's not hard to implement this yourself using [http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Concurrent-MVar.html <tt>MVar</tt>], though it's harder to get the exception handling right.
   
 
[[Category:FAQ]]
 
[[Category:FAQ]]

Revision as of 12:27, 16 August 2011

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.

1 See also

Contents


2 The real world

2.1 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.

2.2 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.

2.3 How can I get started with Haskell right now?

Check out Try Haskell.

2.4 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.

2.5 How can I get help with learning Haskell?

Your options include:

2.6 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.

2.7 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.

2.8 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.

2.9 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.

2.10 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.

2.11 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.

2.12 How do I get libraries for Haskell?

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

2.13 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.

2.14 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".

3 Paradigms

3.1 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.

3.2 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.

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

No; IO in Haskell is straightforward.

3.4 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.

3.5 Wait, is Haskell imperative or is it functional?

Both. In Haskell, functions are first class, and so are imperative actions.

There is no reason to consider "imperative language" and "functional language" as opposites. 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.

4 Math

4.1 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.

4.2 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.

5 Types

5.1 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.

5.2 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.

5.3 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.

5.4 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.

5.5 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
.

5.6 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.

5.7 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 "C 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.

5.8 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.

5.9 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

5.10 How do I convert
IO Int
to
Int
?

You can't; they represent totally different things. An
Int
is an integer. An
IO Int
is a description of how some IO could be performed, in the future, to produce an integer. The IO hasn't been performed yet, and might never happen or might happen more than once.

See the Introduction to IO.

5.11 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.

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

Don't. Instead use

reads :: (Read a) => String -> [(a, String)]

which returns a list of parses, each with a value and a remaining string. An example:

safeRead :: (Read a) => String -> Maybe a
safeRead x = case reads x of
    [(v,"")] -> Just v
    _        -> Nothing

5.13 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.

6 Making it work

6.1 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.

6.2 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.

6.3 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.

6.4 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

6.5 How can I do automated unit testing?

See the testing chapter in Real World Haskell.

6.6 How can I find and fix performance problems?

See the profiling and optimization chapter in Real World Haskell.

7 Modules

7.1 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.

7.2 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)

7.3 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

7.4 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, (*) )

7.5 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

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

module Bar ( module Foo ) where
import Foo

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

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

8 The M-word

See also "What a Monad is not".

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

Absolutely not.

8.2 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"'.

8.3 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.

8.4 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.

8.5 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
.

9 Concurrency and parallelism

See also notes on parallel and concurrent programming.

9.1 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.

9.2 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
.

9.3 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.

9.4 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.

9.5 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.