Gist for Haskell
&&, ||, not , ==, /=(not equal)
Basic functions(prefix or use `` for infix):
succ 8 returns 9
functions can't begin with uppercase letters.
[fname] [...args] = [expression]
if [exp] then [exp] else [exp] else is mandatory
let [ex] for in-line name-defining.
[ls]++[ls] for list appending. prepending
A:[list] is much cheaper than appending.
[ls] !! index Use
!! for list access
head [lst] to extract the 1st element
tail [lst] to extract the rest of the list except 1st elem.
last [lst] to put the last elem
init [lst] to take all but last elem.
null [ls] check for emptiness.
take # [ls] take the first # elements
drop # [ls] drops the first # elements and returns the list.
elem E [ls] checks for E's membership in the list
[2,4,..10] for range with a step
[2,4..] infinite list
[ [expression] | x <- [range] , [condition] ]
similar to tuples in C++. can be heterogeneous.
fst (a,b) and
snd (a,b) are 2 tuple element access functions
a useful function
zip (like Py)
zip [ls1] [ls2] creates a list with pairs
Haskell is static-typing language.
:t FOO use
:t to tell the type of an expression.
:: means 'has the type of '
Functions also have types. When writing our own functions, we can choose to give them an explicit type declaration.
addThree :: Int -> Int -> Int -> Int addThree x y z = x + y + z
type variable. That means that a can be of any type. This is much like generics in other languages,
ghci> :t head head :: [a] -> a
A typeclass is a sort of interface that defines some behavior of a type
ghci> :t (==) (==) :: (Eq a) => a -> a -> Bool
We see a new thing here, the
=> symbol. Everything before the => symbol is called a class constraint. We can read the previous type declaration like this: the equality function takes any two values that are of the same type and returns a Bool. The type of those two values must be a member of the Eq class (this was the class constraint).
Eq for equity-checkable
Ord for ordering
Show has a string representation. a useful function:
show [exp] like
repr in Python. shows the string repr of an expression.
read is the opposite. It interprets given representation and decodes it
ghci> read "True" || False True ghci> read "8.2" + 3.8 12.0 ghci> read "5" - 2 3 ghci> read "[1,2,3,4]" ++  [1,2,3,4,3]
ghci> :t read read :: (Read a) => String -> a
See? It returns a type that's part of Read but if we don't try to use it in some way later, it has no way of knowing which type. That's why we can use explicit type annotations. Type annotations are a way of explicitly saying what the type of an expression should be. We do that by adding :: at the end of the expression and then specifying a type. Observe:
ghci> read "5" :: Int 5 ghci> read "5" :: Float 5.0 ghci> (read "5" :: Float) * 4 20.0
sayMe :: (Integral a) => a -> String sayMe 1 = "One!" sayMe 2 = "Two!" sayMe 3 = "Three!" sayMe 4 = "Four!" sayMe 5 = "Five!" sayMe x = "Not between 1 and 5"
you can also pattern match in list comprehensions.
ghci> let xs = [(1,3), (4,3), (2,4), (5,3), (5,6), (3,1)] ghci> [a+b | (a,b) <- xs] [4,7,6,8,11,4]
Lists themselves can also be used in pattern matching. You can match with the empty list  or any pattern that involves : and the empty list
The x:xs pattern is used a lot, especially with recursive functions. But patterns that have : in them only match against lists of length 1 or more.
head' :: [a] -> a head'  = error "Can't call head on an empty list, dummy!" head' (x:_) = x
Notice that if you want to bind to several variables (even if one of them is just _ and doesn't actually bind at all), we have to surround them in parentheses.
tell :: (Show a) => [a] -> String tell  = "The list is empty" tell (x:) = "The list has one element: " ++ show x tell (x:y:) = "The list has two elements: " ++ show x ++ " and " ++ show y tell (x:y:_) = "This list is long. The first two elements are: " ++ show x ++ " and " ++ show y
you can't use ++ in pattern matches.
max' :: (Ord a) => a -> a -> a max' a b | a > b = a | otherwise = b
bmiTell :: (RealFloat a) => a -> a -> String bmiTell weight height | bmi <= 18.5 = "You're underweight, you emo, you!" | bmi <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!" | bmi <= 30.0 = "You're fat! Lose some weight, fatty!" | otherwise = "You're a whale, congratulations!" where bmi = weight / height ^ 2
where clause for local variables and functions
The names we define in the where section of a function are only visible to that function, so we don't have to worry about them polluting the namespace of other functions. Notice that all the names are aligned at a single column. If we don't align them nice and proper, Haskell gets confused because then it doesn't know they're all part of the same block.
where bindings aren't shared across function bodies of different patterns see below
initials :: String -> String -> String initials firstname lastname = [f] ++ ". " ++ [l] ++ "." where (f:_) = firstname (l:_) = lastname
The form is
let <bindings> in <expression>. The names that you define in the let part are accessible to the expression after the in part. Let bindings let you bind to variables anywhere and are expressions themselves, but are very local, so they don't span across guards. Just like any construct in Haskell that is used to bind values to names, let bindings can be used for pattern matching.
cylinder :: (RealFloat a) => a -> a -> a cylinder r h = let sideArea = 2 * pi * r * h topArea = pi * r ^2 in sideArea + 2 * topArea
The difference is that let bindings are expressions themselves. where bindings are just syntactic constructs.
They can also be used to introduce functions in a local scope:
If we want to bind to several variables inline, we obviously can't align them at columns. That's why we can separate them with semicolons.
ghci> 4 * (let a = 9 in a + 1) + 2 42 ghci> [let square x = x * x in (square 5, square 3, square 2)] [(25,9,4)] ghci> (let a = 100; b = 200; c = 300 in a*b*c, let foo="Hey "; bar = "there!" in foo ++ bar) (6000000,"Hey there!")
case expression of pattern -> result pattern -> result pattern -> result ...
head' :: [a] -> a head' xs = case xs of  -> error "No head for empty lists!" (x:_) -> x
Whereas pattern matching on function parameters can only be done when defining functions, case expressions can be used pretty much anywhere
describeList :: [a] -> String describeList xs = "The list is " ++ case xs of  -> "empty." [x] -> "a singleton list." xs -> "a longer list."
They are useful for pattern matching against something in the middle of an expression. Because pattern matching in function definitions is syntactic sugar for case expressions, we could have also defined this like so:
describeList :: [a] -> String describeList xs = "The list is " ++ what xs where what  = "empty." what [x] = "a singleton list." what xs = "a longer list."