Haskell Cheat Sheet
Haskell Cheat Sheet
Haskell Cheat Sheet
Syntax
Below the most basic syntax for Haskell is given.
Strings
Enumerations
Haskell can be written using braces and semicolons, just like C. However, no one does. Instead,
the layout rule is used, where spaces represent
jgbailey@codeslower.com
case ch of
scope. The general rule is always indent. When As can be seen above, the in keyword must also be
Nothing -> "No choice!"
in the same column as let. Finally, when multiple
the compiler complains, indent more.
Just (First _) -> "First!"
defintions are given, all identifiers must appear in
Braces and semi-colons
Semi-colons terminate
Just Second -> "Second!"
the same column.
an expression, and braces represent scope. They
_ -> "Something else."
can be used after several keywords: where, let, do
and of. They cannot be used when defining a func- Keywords
We can use argument capture to display the value
tion body. For example, the below will not compile.
matched if we wish:
Haskell keywords are listed below, in alphabetical
square2 x = { x * x; }
anyChoice2 ch =
order.
case ch of
However, this will work fine:
Nothing -> "No choice!"
Case
square2 x = result
Just score@(First "gold") ->
where { result = x * x; }
"First with gold!"
case is similar to a switch statement in C# or Java,
Just score@(First _) ->
but can take action based on any possible value for
Function Definition
Indent the body at least the type of the value being inspected. Consider a
"First with something else: "
one space from the function name:
++ show score
simple data type such as the following:
_ -> "Not first."
square x =
data Choices = First String | Second |
x * x
Third | Fourth
Matching Order
Matching proceeds from top to
bottom. If we re-wrote anyChoice1 as below, well
Unless a where clause is present. In that case, incase can be used to determine which choice was
never know what choice was actually given because
dent the where clause at least one space from the
given:
the first pattern will always succeed:
function name and any function bodies at least one
space from the where keyword:
whichChoice ch =
anyChoice3 ch =
case
ch
of
case ch of
square x =
First
_
->
"1st!"
_ -> "Something else."
x2
Second -> "2nd!"
Nothing -> "No choice!"
where x2 =
_
->
"Something
else."
Just (First _) -> "First!"
x * x
Just Second -> "Second!"
As with pattern-matching in function definitions,
Let
Indent the body of the let at least one space
the _ character is a wildcard and matches any
Guards
Guards, or conditional matches, can be
from the first definition in the let. If let appears
value.
used in cases just like function definitions. The only
on its own line, the body of any defintion must apNesting & Capture
Nested matching and argu- difference is the use of the -> instead of =. Here
pear in the column after the let:
ment capture are also allowed. Referring to the is a simple function which does a case-insensitive
square x =
definition of Maybe below, we can determine if any string match:
let x2 =
choice was given using a nested match:
strcmp [] [] = True
x * x
strcmp s1 s2 = case (s1, s2) of
anyChoice1 ch =
in x2
c 2008 Justin Bailey.
jgbailey@codeslower.com
(s1:ss1, s2:ss2)
| toUpper s1 == toUpper s2 ->
strcmp ss1 ss2
| otherwise -> False
_ -> False
Class
A Haskell function is defined to work on a certain
type or set of types and cannot be defined more
than once. Most languages support the idea of
overloading, where a function can have different
behavior depending on the type of its arguments.
Haskell accomplishes overloading through class
and instance declarations. A class defines one
or more functions that can be applied to any types
which are members (i.e., instances) of that class. A
class is analagous to an interface in Java or C, and
instances to a concrete implementation of the interface.
A class must be declared with one or more type
variables. Technically, Haskell 98 only allows one
type variable, but most implementations of Haskell
support so-called multi-parameter type classes, which
allow more than one type variable.
We can define a class which supplies a flavor for
a given type:
Data
Notice that the declaration only gives the type sig- So-called algebraic data types can be declared as folnature of the function - no implementation is given lows:
here (with some exceptions, see Defaults below).
data MyType = MyValue1 | MyValue2
Continuing, we can define several instances:
MyType is the types name.
MyValue1 and
MyValue are values of the type and are called coninstance Flavor Bool where
structors. Multiple constructors are separated with
flavor _ = "sweet"
c 2008 Justin Bailey.
Class Constraints
Data types can be declared
with class constraints on the type variables, but
data Slot2 a = Slot2 a Int | Empty2
this practice is generally discouraged. It is generAbove, the Slot2 constructor can take a value of ally better to hide the raw data constructors using the module system and instead export smart
any type and an Int value.
constructors which apply appropriate constraints.
Record Syntax
Constructor arguments can be
In any case, the syntax used is:
declared either positionally, as above, or using
record syntax, which gives a name to each argudata (Num a) => SomeNumber a = Two a a
ment. For example, here we declare a Contact type
| Three a a a
with names for appropriate arguments:
This declares a type SomeNumber which has one
data Contact = Contact { ctName :: String type variable argument. Valid types are those in
the Num class.
, ctEmail :: String
, ctPhone :: String }
Deriving
Many types have common operations
These names are referred to as selector or accessor
functions and are just that, functions. They must
start with a lowercase letter or underscore and cannot have the same name as another function in
scope. Thus the ct prefix on each above. Multiple constructors (of the same type) can use the
same accessor function for values of the same type,
but that can be dangerous if the accessor is not used
by all constructors. Consider this rather contrived
example:
Deriving
See the section on deriving under the data keyword above.
Do
The do keyword indicates that the code to follow
will be in a monadic context. Statements are separated by newlines, assignment is indicated by <-,
and a let form is introduce which does not require
the in keyword.
If and IO
if is tricky when used with IO.
Conceptually it is are no different, but intuitively
which are tediuos to define yet very necessary, such it is hard to deal with. Consider the function
as the ability to convert to and from strings, com- doesFileExists from System.Directory:
pare for equality, or order in a sequence. These
capabilities are defined as typeclasses in Haskell.
doesFileExist :: FilePath -> IO Bool
Because seven of these operations are so common, Haskell provides the deriving keyword The if statement has this signature:
which will automatically implement the typeclass
if-then-else :: Bool -> a -> a -> a
on the associated type. The seven supported typeclasses are: Eq, Read, Show, Ord, Enum, Ix, and
That is, it takes a Bool value and evaluates to some
Bounded.
other value based on the condition. From the type
Two forms of deriving are possible. The first is
signatures it is clear that doesFileExist cannot be
used when a type only derives on class:
used directly by if:
wrong fileName =
if doesFileExist fileName
then ...
else ...
jgbailey@codeslower.com
right1 fileName = do
exists <- doesFileExist fileName
if exists
then return 1
else return 0
Notice the use of return, too. Because do puts us
inside the IO monad, we cant get out except
through return. Note that we dont have to use
if inline here - we can also use let to evaluate the
condition and get a value first:
right2 fileName = do
exists <- doesFileExist fileName
let result =
if exists
then 1
else 0
return result
else
-- multiple statements require
-- a new 'do'.
do
f <- readFile args
putStrLn ("The file is " ++
show (length f)
++ " bytes long.")
And one with case:
countBytes2 =
do
putStrLn "Enter a filename."
args <- getLine
case args of
[] -> putStrLn "No args given."
file -> do
f <- readFile file
putStrLn ("The file is " ++
show (length f)
++ " bytes long.")
Export
See the section on module below.
-- Use pattern-matching to
-- get first character
sentenceCase (s:rest) =
if isLower s
then toUpper s : rest
else s : rest
-- Anything else is empty string
sentenceCase _ = []
Import
countBytes1 f =
do
putStrLn "Enter a filename."
args <- getLine
if length args == 0
-- no 'do'.
then putStrLn "No filename given."
c 2008 Justin Bailey.
countBytes3 =
do
putStrLn "Enter a filename."
args <- getLine
case args of
[] -> putStrLn "No args given."
file -> do { f <- readFile file;
putStrLn ("The file is " ++
show (length f)
++ " bytes long."); }
5
See let.
Instance
See the section on class above.
jgbailey@codeslower.com
Let
Local functions can be defined within a function using let. let is always followed by in. in must appear in the same column as the let keyword. Functions defined have access to all other functions and Note that this is different than the following, which
variables within the same scope (including those only works if the string has three characters:
defined by let). In this example, mult multiplies
onlyThree str =
its argument n by x, which was passed to the origlet (a:b:c) = str
inal multiples. mult is used by map to give the
in "The characters given are: " ++
multiples of x up to 10:
show a ++ ", " ++ show b ++
", and " ++ show c
multiples x =
let mult n = n * x
in map mult [1..10]
firstThree str =
let (a:b:c:_) = str
c 2008 Justin Bailey.
Of
Imports
The Haskell standard libraries are divided into a number of modules. The functionality
provided by those libraries is accessed by importing into your source file. To import all everything
exported by a library, just use the module name:
import Text.Read
Everything means everything: functions, data types
and constructors, class declarations, and even other
modules imported and then exported by the that
module. Importing selectively is accomplished by
giving a list of names to import. For example, here
we import some functions from Text.Read:
Module
Note that, unlike data types, all class functions are A second form does not create an alias. Instead,
imported unless explicitly excluded. To only import the prefix becomes the module name. We can write
a simple function to check if a string is all upper
the class, we use this syntax:
case:
import Text.Read (Read())
import qualified Char
allUpper str =
Exclusions
If most, but not all, names are going
all Char.isUpper str
to imported from a module, it would be tedious to
specify all those names except a few. For that reaimport Data.Set
Except for the prefix specified, qualified imports
son, imports can also be specified via the hiding
import Data.Char
support the same syntax as normal imports. The
keyword:
name imported can be limited in the same ways as
described above.
Newtype
import Data.Char hiding (isControl
, isMark)
Exports
If an export list is not provided, then all
functions, types, constructors, etc. will be available
to anyone importing the module. Note that any imported modules are not exported in this case. Limiting the names exported is accomplished by adding
a parenthesized list of names before the where keyword:
Qualified Imports
The names exported by a
module (i.e., functions, types, operators, etc.) can
have a prefix attached through qualified imports.
This is particularly useful for modules which have
a large number of functions having the same name The same syntax as used for importing can be used
as Prelude functions. Data.Set is a good example: here to specify which functions, types, constructors, and classes are exported, with a few differimport qualified Data.Set as Set
ences. If a module imports another module, it can
also export that module:
This form requires any function, type, constructor
module MyBigModule (module Data.Set
or other name exported by Data.Set to now be pre, module Data.Char)
fixed with the alias (i.e., Set) given. Here is one way
where
to remove all duplicates from a list:
removeDups a =
Set.toList (Set.fromList a)
c 2008 Justin Bailey.
import Data.Set
import Data.Char
7
jgbailey@codeslower.com
The key observation is that this keyword does not Because type introduces a synonym, type checking
introduce a new value; instead it introduces a new is not affected in any way. The function lower, defined as:
type. This gives us two very useful properties:
strlen [] = result
where result = "No string given!"
strlen f = result ++ " characters long!"
where result = show (length f)
Type
Function Definition
jgbailey@codeslower.com
isEven 0 = True
isEven 1 = False
isEven (n + 2) = isEven n
Guards
Boolean functions can be used as
Pattern-matching also allows values to be assigned guards in function definitions along with pattern
to variables. For example, this function determines matching. An example without pattern matching:
if the string given is empty or not. If not, the value
which n
captures in str is converted to to lower case:
| n == 0 = "zero!"
toLowerStr [] = []
| even n = "even!"
toLowerStr str = map toLower str
| otherwise = "odd!"
In reality, str is the same as _ in that it will match
Notice otherwise it always evaulates to true and
anything, except the value matched is also given a
can be used to specify a default branch.
name.
Guards can be used with patterns. Here is a
n + k Patterns
This sometimes controversial function that determines if the first character in a
pattern-matching facility makes it easy to match string is upper or lower case:
certain kinds of numeric expressions. The idea
what [] = "empty string!"
is to define a base case (the n portion) with a
what (c:_)
constant number for matching, and then to define
| isUpper c = "upper case!"
other matches (the k portion) as additives to the
| isLower c = "lower case"
base case. Here is a rather inefficient way of testing
| otherwise = "not a letter!"
if a number is even or not:
c 2008 Justin Bailey.
Record Syntax
Normally pattern matching occurs based on the position of arguments in the
value being matched. Types declared with record
syntax, however, can match based on those record
names. Given this data type:
ups =
As long as the value x is not actually evaluated,
[c | c <- [minBound .. maxBound]
were safe. None of the base types need to look at x
, isUpper c]
(see the _ matches they use), so things will work
just fine.
Or to find all occurrences of a particular break
One wrinkle with the above is that we must
value br in a list word (indexing from 0):
provide type annotations in the interpreter or the
code when using a Nothing constructor. Nothing
idxs word br =
has type Maybe a but, if not enough other informa[i | (i, c) <- zip [0..] word
tion is available, Haskell must be told what a is.
, c == br]
Some example default values:
class Def a where
A unique feature of list comprehensions is that pat-- Return "Just False"
defValue :: a -> a
tern matching failures do not cause an error - they
defMB = defValue (Nothing :: Maybe Bool) are just excluded from the resulting list.
The idea is you give defValue a value of the right
-- Return "Just ' '"
type and it gives you back a default value for that
defMC = defValue (Nothing :: Maybe Char)
Operators
type. Defining instances for basic types is easy:
Lazy Patterns
This syntax, also known as irrefutable patterns, allows pattern matches which always succeed. That means any clause using the
pattern will succeed, but if it tries to actually use
the matched value an error may occur. This is generally useful when an action should be taken on
the type of a particular value, even if the value isnt
present.
For example, define a class for default values:
List Comprehensions
A list comprehension consists of three types of elements - generators, guards, and targets. A list cominstance Def Char where
prehension creates a list of target values based on
defValue _ = ' '
the generators and guards given. This comprehenMaybe is a littler trickier, because we want to get sion generates all squares:
a default value for the type, but the constructor
squares = [x * x | x <- [1..]]
might be Nothing. The following definition would
work, but its not optimal since we get Nothing x <- [1..] generates a list of all Integer values
and puts them in x, one by one. x * x creates each
when Nothing is passed in.
element of the list by multiplying x by itself.
instance Def a => Def (Maybe a) where
Guards allow certain elements to be excluded.
defValue (Just x) = Just (defValue x)
The following shows how divisors for a given numdefValue Nothing = Nothing
ber (excluding itself) can be calculated. Notice how
d is used in both the guard and target expression.
Wed rather get a Just (default value) back instead.
Here is where a lazy pattern saves us we can predivisors n =
tend that weve matched Just x and use that to get
[d | d <- [1..(n `div` 2)]
a default value, even if Nothing is given:
, n `mod` d == 0]
3 + 4 == (+) 3 4
To define a new operator, simply define it as a normal function, except the operator appears between
the two arguments. Heres one which takes inserts
a comma between two strings and ensures no extra
spaces appear:
first ## last =
let trim s = dropWhile isSpace
(reverse (dropWhile isSpace
(reverse s)))
in trim last ++ ", " ++ trim first
> " Haskell " ## " Curry "
Curry, Haskell
jgbailey@codeslower.com
Of course, full pattern matching, guards, etc. are The results are surprising:
available in this form. Type signatures are a bit dif> 2 + 3 * 5
ferent, though. The operator name must appear
17
in parenetheses:
> 2 `plus1` 3 `mult1` 5
(##) :: String -> String -> String
25
isL33t _ =
toL33t 'o'
toL33t 'a'
-- etc.
toL33t c =
False
= '0'
= '4'
c
div1 a b = a / b
However, there are several operators which cannot be redefined. Those are:
We get interesting results:
<- -> = (by itself )
> 20 / 2 / 2
Precedence & Associativity
The precedence
5.0
and associativity, collectively called fixity, of any
> 20 `div1` 2 `div1` 2
operator can be set through the infix, infixr and
20.0
infixl keywords. These can be applied both to
top-level functions and to local definitions. The
Currying
syntax is:
infix | infixr | infixl precedence op
where precedence varies from 0 to 9. Op can actually be any function which takes two arguments
(i.e., any binary operation). Whether the operator
is left or right associative is specified by infixl or
infixr, respectively. infix declarations have no associativity.
Precedence and associativity make many of the
rules of arithmetic work as expected. For example, consider these minor updates to the precedence of addition and multiplication:
infixl 8 `plus1`
plus1 a b = a + b
infixl 7 `mult1`
mult1 a b = a * b
c 2008 Justin Bailey.
jgbailey@codeslower.com
signature represents a new function which can be The above is a bit verbose and we can rewrite using record syntax. This kind of update only sets
created by supplying one more argument.
values for the field(s) specified and copies the rest:
Sections
Operators are functions, and they can
be curried like any other. For example, a curried
noGreen2 c = c { green = 0 }
version of + can be written as:
Above, we capture the Color value in c and return
add10 = (+) 10
a new Color value. That value happens to have the
same value for red and blue as c and its green
However, this can be unwieldy and hard to read.
component is 0. We can combine this with pattern
Sections are curried operators, using parenthematching to set the green and blue fields to equal
ses. Here is add10 using sections:
the red field:
add10 = (10 +)
Of course, lambdas can be the returned from functions too. This classic returns a function which will
then multiply its argument by the one originally
given:
multBy n = \m -> n * m
For example:
Type Signatures
12
jgbailey@codeslower.com
Type signatures can appear on top-level functions and nested let or where definitions. Generally this is useful for documentation, though in
some case you may use it prevent polymorphism.
A type signature is first the name of the item which
will be typed, followed by a ::, followed by the
types. An example of this has already been seen
above.
Type signatures do not need to appear directly
above their implementation. They can be specified
anywhere in the containing module (yes, even below!). Multiple items with the same signature can
also be defined together:
Unit
neg y | y > 0 = negate y
| otherwise = y
Type Annotations
Sometimes Haskell will not be able to deter- Contributors
mine what type you meant. The classic demonstraMy thanks to those who contributed patches and
tion of this is the show . read problem:
useful suggestions: Cale Gibbard, Stephen Hicks,
Kurt Hutchinson, Adrian Neumann, Markus
canParseInt x = show (read x)
Roberts, Holger Siegel, and Jeff Zaroyko.
Haskell cannot compile that function because it
does not know the type of x. We must limit the
Version
type through an annotation:
1 git://github.com/m4dc4p/cheatsheet.git
2 http://hackage.haskell.org/cgi-bin/hackage-scripts/package/CheatSheet
3 http://blog.codeslower.com
13
jgbailey@codeslower.com