views:

3732

answers:

25

What are the lesser-known but useful features of the Haskell programming language. (I understand the language itself is lesser-known, but work with me. Even explanations of the simple things in Haskell, like defining the Fibonacci sequence with one line of code, will get upvoted by me.)

  • Try to limit answers to the Haskell core
  • One feature per answer
  • Give an example and short description of the feature, not just a link to documentation
  • Label the feature using bold title as the first line
+12  A: 

Optional Layout

You can use explicit braces and semicolons instead of whitespace (aka layout) to delimit blocks.

let {
      x = 40;
      y = 2
     } in
 x + y

... or equivalently...

let { x = 40; y = 2 } in x + y

... instead of ...

let x = 40
    y = 2
 in x + y

Because layout is not required, Haskell programs can be straightforwardly produced by other programs.

Jonathan Tran
+14  A: 

Operator Fixity

You can use the infix, infixl or infixr keywords to define operators associativity and precedence. Example taken from the reference:

main = print (1 +++ 2 *** 3)

infixr  6 +++
infixr  7 ***,///

(+++) :: Int -> Int -> Int
a +++ b = a + 2*b

(***) :: Int -> Int -> Int
a *** b = a - 4*b

(///) :: Int -> Int -> Int
a /// b = 2*a - 3*b
Output: -19

The number (0 to 9) after the infix allows you to define the precedence of the operator, being 9 the strongest. Infix means no associativity, whereas infixl associates left and infixr associates right.

This allows you to define complex operators to do high level operations written as simple expressions.

Note that you can also use binary functions as operators if you place them between backticks:

main = print (a `foo` b)

foo :: Int -> Int -> Int
foo a b = a + b

And as such, you can also define precedence for them:

infixr 4 `foo`
Santiago Palladino
Aren't they backticks, actually? Prelude> print (a `foo` b) 6
bortzmeyer
Yes, those should be backticks. Are there really people who consider this to be a hidden feature?
Jonathan Tran
Changed ticks to backticks, my mistake. And whether it is considered a hidden feature or not, it depends on how much knowledge you have on the language. Sorry if you didnt like it.
Santiago Palladino
"Infix means no associativity" -- how is that possible? If I do `infix 6 +++` then how does `1 +++ 2 +++ 3` get evaluated? It seems to me it must be either `(1 +++ 2) +++ 3` or `1 +++ (2 +++ 3)`. Even those might evaluate to the same thing, Haskell must pick one or the other to actually *do*, right?
MatrixFrog
+14  A: 

seq and ($!) only evaluate enough to check that something is not bottom.

The following program will only print "there".

main = print "hi " `seq` print "there"

For those unfamiliar with Haskell, Haskell is non-strict in general, meaning that an argument to a function is only evaluated if it is needed.

For example, the following prints "ignored" and terminates with success.

main = foo (error "explode!")
  where foo _ = print "ignored"

seq is known to change that behavior by evaluating to bottom if its first argument is bottom.

For example:

main = error "first" `seq` print "impossible to print"

... or equivalently, without infix ...

main = seq (error "first") (print "impossible to print")

... will blow up with an error on "first". It will never print "impossible to print".

So it might be a little surprising that even though seq is strict, it won't evaluate something the way eager languages evaluate. In particular, it won't try to force all the positive integers in the following program. Instead, it will check that [1..] isn't bottom (which can be found immediately), print "done", and exit.

main = [1..] `seq` print "done"
Jonathan Tran
What do you mean 'not bottom'?
Claudiu
Added an explanation. Does that answer your question?
Jonathan Tran
Basically, "bottom" is any undefined value like the result of calling error. Something that loops forever is also called bottom.
Jonathan Tran
Ah, thanks, that clears it up! How can it check that something loops forever? Isn't that the halting problem, which is impossible to decide?
Claudiu
Also, doesn't [1..] loop forever? (It at least generates an infinite amount of integers
Claudiu
I believe that if something loops forever, calling seq on it will also loop forever. [1..] generates an infinite number of integers. Due to laziness, they won't actually get computed until you try to grab one, and seq doesn't do that.
Jonathan Tran
[1..] simply evaluates to 1:[2..], that is, the list that starts with 1, followed by another list. It only loops forever if you try to get to the end of the list.
ephemient
Also, GHC does detect (some) infinite loops -- you can define "loop = loop" just fine, but if you try to print the value of "loop", it will error "<<loop>>".
ephemient
more reading about the value bottom: http://haskell.org/haskellwiki/Bottom
Jared Updike
+8  A: 

Infinite Lists

Since you mentioned fibonacci, there is a very elegant way of generating fibonacci numbers from an infinite list like this:

[email protected](1:tfib)    = 1 : 1 : [ a+b | (a,b) <- zip fib tfib ]

The @ operator allows you to use pattern matching on the 1:tfib structure while still referring to the whole pattern as fib.

Note that the comprehension list enters an infinite recursion, generating an infinite list. However, you can request elements from it or operate them, as long as you request a finite amount:

take 10 fib

You can also apply an operation to all elements before requesting them:

take 10 (map (\x -> x+1) fib)

This is thanks to Haskell's lazy evaluation of parameters and lists.

Santiago Palladino
Syntax extensions in GHC let you write this now: fib = 1 : 1 : [ a+b | a <- fib | b <- tail fib ]; however I'd write it 1:1:zipWith (+) fib (tail fib)
ephemient
Your first example actually demonstrates an even more hidden feature of Haskell: you can use full patterns when defining values/functions!
Martijn
+11  A: 

Shorthand for a common list operation

The following are equivalent:

concat $ map f list
concatMap f list
list >>= f

Edit

Since more details were requested...

concat :: [[a]] -> [a]

concat takes a list of lists and concatenates them into a single list.

map :: (a -> b) -> [a] -> [b]

map maps a function over a list.

concatMap :: (a -> [b]) -> [a] -> [b]

concatMap is equivalent to (.) concat . map: map a function over a list, and concatenate the results.

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

A Monad has a bind operation, which is called >>= in Haskell (or its sugared do-equivalent). List, aka [], is a Monad. If we substitute [] for m in the above:

instance Monad [] where
    (>>=) :: [a] -> (a -> [b]) -> [b]
    return :: a -> [a]

What's the natural thing for the Monad operations to do on a list? We have to satisfy the monad laws,

return a >>= f           ==  f a
ma >>= (\a -> return a)  ==  ma
(ma >>= f) >>= g         ==  ma >>= (\a -> f a >>= g)

You can verify that these laws hold if we use the implementation

instance Monad [] where
    (>>=) = concatMap
    return = (:[])

return a >>= f  ==  [a] >>= f  ==  concatMap f [a]  ==  f a
ma >>= (\a -> return a)  ==  concatMap (\a -> [a]) ma  ==  ma
(ma >>= f) >>= g  ==  concatMap g (concatMap f ma)  ==  concatMap (concatMap g . f) ma  ==  ma >>= (\a -> f a >>= g)

This is, in fact, the behavior of Monad []. As a demonstration,

double x = [x,x]
main = do
    print $ map double [1,2,3]
        -- [[1,1],[2,2],[3,3]]
    print . concat $ map double [1,2,3]
        -- [1,1,2,2,3,3]
    print $ concatMap double [1,2,3]
        -- [1,1,2,2,3,3]
    print $ [1,2,3] >>= double
        -- [1,1,2,2,3,3]
ephemient
Should I split this into multiple answers?
ephemient
Would you rather get 1 up vote (or possibly 1 down for not following the question's rules) or 1 up vote for each feature?
Jonathan Tran
Well then. Here comes the flood...
ephemient
i don't quite follow the way this works - can you explain it a bit more?
Claudiu
List is an instance of Monad. >>= for lists concatenates.
Jonathan Tran
That should be (>>=) = flip concatMap.
Martijn
@Martijn: Right. I guess nobody else noticed that `(>>=) = concatMap` doesn't typecheck ;)
ephemient
After getting a bit more familiarity with it, I think the List Monad is a bit problematic... The complaint is that this isn't the only possible way to make a List follow the Monadic laws. Note the answer says "if we use the implementation" - but why should we be forced to use this implementation? Another valid implementation would be similar to the Maybe Monad, where an empty list is equivalent to Nothing and a non-empty list is equivalent to Just first element... Maybe not the best example, but I think the point remains.
Aidan Cully
The List Monad definitely isn't the only possible or reasonable implementation to satisfy the Monad rules, but it's the one that's documented in the Haskell report, and is the most useful. If it worked like `Maybe`, `[x | x <- xs]` and `do x <- xs; return x` would no longer be equivalent.
ephemient
+7  A: 

Readable function composition

Prelude defines (.) to be mathematical function composition; that is, g . f first applies f, then applies g to the result.

If you import Control.Arrow, the following are equivalent:

g . f
f >>> g

Control.Arrow provides an instance Arrow (->), and this is nice for people who don't like to read function application backwards.

ephemient
Note also that `(<<<) = (.)` :)
Porges
+10  A: 

Avoiding parentheses

The (.) and ($) functions in Prelude have very convenient fixities, letting you avoid parentheses in many places. The following are equivalent:

f (g (h x))
f $ g $ h x
f . g $ h x
f . g . h $ x

flip helps too, the following are equivalent:

map (\a -> {- some long expression -}) list
flip map list $ \a ->
    {- some long expression -}
ephemient
I prefer parentheses. They are more explicit.
bortzmeyer
I prefer to eliminate parentheses wherever possible, even when I'm working in less convenient languages like C (under the assumption that everybody reading my code *must know* all operator precedences). It's a matter of taste.
ephemient
pointless notation is real expressive once you get used to it. It's just a list of sequential verbs.
pitr
I come from Java so not using parentheses in Haskell is a pleasure.
nagnatron
+11  A: 

Nestable multiline comments.

{- inside a comment,
     {- inside another comment, -}
still commented! -}
ephemient
How about nestable single-line comments? ;-)
Jonas Kölker
+10  A: 

Pretty guards

Prelude defines otherwise = True, making complete guard conditions read very naturally.

fac n
  | n < 1     = 1
  | otherwise = n * fac (n-1)
ephemient
+7  A: 

If you're looking for a list or higher-order function, it's already there

There's sooo many convenience and higher-order functions in the standard library.

-- factorial can be written, using the strict HOF foldl':
fac n = Data.List.foldl' (*) 1 [1..n]
-- there's a shortcut for that:
fac n = product [1..n]
-- and it can even be written pointfree:
fac = product . enumFromTo 1
ephemient
+6  A: 

Flexible specification of module imports and exports

Importing and exporting is nice.

module Foo (module Bar, blah)  -- this is module Foo, export everything that Bar expored, plus blah

import qualified Some.Long.Name as Short
import Some.Long.Name (name)  -- can import multiple times, with different options

import Baz hiding (blah)  -- import everything from Baz, except something named 'blah'
ephemient
+15  A: 

My brain just exploded

If you try to compile this code:

{-# LANGUAGE ExistentialQuantification #-}
data Foo = forall a. Foo a
ignorefoo f = 1 where Foo a = f

You will get this error message:

$ ghc Foo.hs

Foo.hs:3:22:
    My brain just exploded.
    I can't handle pattern bindings for existentially-quantified constructors.
    Instead, use a case-expression, or do-notation, to unpack the constructor.
    In the binding group for
        Foo a
    In a pattern binding: Foo a = f
    In the definition of `ignorefoo':
        ignorefoo f = 1
                    where
                        Foo a = f
ephemient
I think the following should still give this error:ignorefoo f = 1 where (Foo a) = f
Jason Dagit
Ah, you're right, **that**'s what makes GHC's brain explode. I didn't *think* they had fixed it yet, but I couldn't make my simple example break...
ephemient
+28  A: 

User-defined control structures

Haskell has no shorthand ternary operator. The built-in if-then-else is always ternary, and is an expression (imperative languages tend to have ?:=expression, if=statement). If you want, though,

True ? x = const x
False ? _ = id

will define (?) to be the ternary operator:

(a ? b $ c)  ==  (if a then b else c)

You'd have to resort to macros in most other languages to define your own short-circuiting logical operators, but Haskell is a fully lazy language, so it just works.

-- prints "I'm alive! :)"
main = True ? putStrLn "I'm alive! :)" $ error "I'm dead :("
ephemient
this is awesome
pitr
+10  A: 

Generalized algebraic data types. Here's an example interpreter where the type system lets you cover all the cases:

{-# LANGUAGE GADTs #-}
module Exp
where

data Exp a where
  Num  :: (Num a) => a -> Exp a
  Bool :: Bool -> Exp Bool
  Plus :: (Num a) => Exp a -> Exp a -> Exp a
  If   :: Exp Bool -> Exp a -> Exp a -> Exp a 
  Lt   :: (Num a, Ord a) => Exp a -> Exp a -> Exp Bool
  Lam  :: (a -> Exp b) -> Exp (a -> b)   -- higher order abstract syntax
  App  :: Exp (a -> b) -> Exp a -> Exp b
 -- deriving (Show) -- failse

eval :: Exp a -> a
eval (Num n)      = n
eval (Bool b)     = b
eval (Plus e1 e2) = eval e1 + eval e2
eval (If p t f)   = eval $ if eval p then t else f
eval (Lt e1 e2)   = eval e1 < eval e2
eval (Lam body)   = \x -> eval $ body x
eval (App f a)    = eval f $ eval a

instance Eq a => Eq (Exp a) where
  e1 == e2 = eval e1 == eval e2

instance Show (Exp a) where
  show e = "<exp>" -- very weak show instance

instance (Num a) => Num (Exp a) where
  fromInteger = Num
  (+) = Plus
Norman Ramsey
+1, A full dependently typed programming language like Agda is quite hard to understand/work with (at least to me :-). But GADTs already bring some of the big benefits of dependent types to Haskell, without adding too much of a mental burden for my brain.
Tom Lokhorst
+11  A: 

Patterns in top-level bindings

five :: Int
Just five = Just 5

a, b, c :: Char
[a,b,c] = "abc"

How cool is that! Saves you that call to fromJust and head every now and then.

Martijn
+14  A: 

Hoogle

Hoogle is your friend. I admit, it's not part of the "core", so cabal install hoogle

Now you know how "if you're looking for a higher-order function, it's already there" (ephemient's comment). But how do you find that function? With hoogle!

$ hoogle "Num a => [a] -> a"
Prelude product :: Num a => [a] -> a
Prelude sum :: Num a => [a] -> a

$ hoogle "[Maybe a] -> [a]"
Data.Maybe catMaybes :: [Maybe a] -> [a]

$ hoogle "Monad m => [m a] -> m [a]"
Prelude sequence :: Monad m => [m a] -> m [a]

$ hoogle "[a] -> [b] -> (a -> b -> c) -> [c]"
Prelude zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

The hoogle-google programmer is not able to write his programs on paper by himself the same way he does with the help of the computer. But he and the machine together are a forced not* to be reckoned with.

Btw, if you liked hoogle be sure to check out hlint!

yairchu
Hoogle is also available online at http://haskell.org/hoogle/
ShreevatsaR
This is the best API searching tool that I have ever come accross. Because most of the time you know roughly what you are searching for; as in what it should do. This lets you search for anything that looks like that.
Robert Massaioli
+6  A: 

Equational Reasoning

Haskell, being purely functional allows you to read an equal sign as a real equal sign (in the absence of non-overlapping patterns).

This allows you to substitute definitions directly into code, and in terms of optimization gives a lot of leeway to the compiler about when stuff happens.

A good example of this form of reasoning can be found here:

http://www.haskell.org/pipermail/haskell-cafe/2009-March/058603.html

This also manifests itself nicely in the form of laws or RULES pragmas expected for valid members of an instance, for instance the Monad laws:

  1. returrn a >>= f == f a
  2. m >>= return == m
  3. (m >>= f) >>= g == m >>= (\x -> f x >>= g)

can often be used to simplify monadic code.

Edward Kmett
+5  A: 

Free Theorems

Phil Wadler introduced us to the notion of a free theorem and we've been abusing them in Haskell ever since.

These wonderful artifacts of Hindley-Milner-style type systems help out with equational reasoning by using parametricity to tell you about what a function will not do.

For instance, there are two laws that every instance of Functor should satisfy:

  1. forall f g. fmap f . fmap g = fmap (f . g)
  2. fmap id = id

But, the free theorem tells us we need not bother proving the first one, but given the second it comes for 'free' just from the type signature!

fmap :: Functor f => (a -> b) -> f a -> f b

You need to be a bit careful with laziness, but this is partially covered in the original paper, and in Janis Voigtlaender's more recent paper on free theorems in the presence of seq.

Edward Kmett
+1 I totally did not know about this but it is really cool; why isn't this higher. That removes alot of proof work if you can derive a result straight from the type signature. Reading about it now.
Robert Massaioli
+2  A: 

Enhanced pattern matching

  • Lazy patterns
  • Irrefutable patterns

    let ~(Just x) = someExpression
    

See pattern matching

Dario
This gives a compiler error: Occurs check: cannot construct the infinite type: t = Maybe t
Martijn
+1  A: 

Monads

They are not that hidden, but they are simply everywhere, even where you don't think of them (Lists, Maybe-Types) ...

Dario
They really are and Monads, and the other type classes that surround them are so powerful that you would be a fool not to use them in every language you could. I believe that 'The Monad.Reader' Issue thirteen has a really good explanation of how it all comes together.
Robert Massaioli
+5  A: 

Parallel list comprehension

(Special GHC-feature)

  fibs = 0 : 1 : [ a + b | a <- fibs | b <- tail fibs ]
Dario
+4  A: 

Laziness

Ubiquitous laziness means you can do things like define

fibs = 1 : 1 : zipWith (+) fibs (tail fibs)

But it also provides us with a lot of more subtle benefits in terms of syntax and reasoning.

For instance, due to strictness ML has to deal with the value restriction, and is very careful to track circular let bindings, but in Haskell, we can let every let be recursive and have no need to distinguish between val and fun. This removes a major syntactic wart from the language.

This indirectly gives rise to our lovely where clause, because we can safely move computations that may or may not be used out of the main control flow and let laziness deal with sharing the results.

We can replace (almost) all of those ML style functions that need to take () and return a value, with just a lazy computation of the value. There are reasons to avoid doing so from time to time to avoid leaking space with CAFs, but such cases are rare.

Finally, it permits unrestricted eta-reduction (\x -> f x can be replaced with f). This makes combinator oriented programming for things like parser combinators much more pleasant than working with similar constructs in a strict language.

This helps you when reasoning about programs in point-free style, or about rewriting them into point-free style and reduces argument noise.

Edward Kmett
+5  A: 

let 5 = 6 in ... is valid Haskell.

Martijn
Does let 5 = 6 ... have any effect?
I. J. Kennedy
Its the constant pattern `5` matched against the value `6`, but since let-bindings are completely lazy, the match will never be attempted.
SealedSun
[head explodes]
Jared Updike
+2  A: 

Enumerations

Any type which is an instance of Enum can be used in an arithmetic sequence, not just numbers:

alphabet :: String
alphabet = ['A' .. 'Z']

Including your own datatypes, just derive from Enum to get a default implementation:

data MyEnum = A | B | C deriving(Eq, Show, Enum)

main = do
    print $ [A ..]                 -- prints "[A,B,C]"
    print $ map fromEnum [A ..]    -- prints "[0,1,2]"
+6  A: 

C-Style Enumerations

Combining top-level pattern matching and arithmetic sequences gives us a handy way to define consecutive values:

foo : bar : baz : _ = [100 ..]    -- foo = 100, bar = 101, baz = 102