A Haskell A Day: Quick Start

By Xah Lee. Date:

{- comments are enclosed between braces with a dash,
like this paragraph. -}

-- alternatively, comment starts with two dashes and ends at the end of line.

-- assign a variable

-- assign a string
somestring = "somestring"

-- a item's type can be declared explicitly:
stringtwo :: String
stringtwo = "another string"

{- all data in Haskell has a type.
Almost always, the type declaration can be omitted,
because Haskell can figure it out for you. -}

Defining a Function

{- declare the function's type.
This means, add1 is a function, which takes one argument of type Integer
and returns a data of type Integer -}

-- This defines the body of add1:
add1 x = x + 1

-- example of using the function.

{- anonymous function. Note that \x indicates parameter,
and “->” is used instead of the equal sign = -}
\x -> x + 2

-- apply a anonymous function to a expression
@eval (\x -> x + 2) 1

-- anonymous function can be assigned to variable
add2 = (\x -> x + 2)
-- this is equivalent as the definition “add2 x = x + 2”

-- defining function with two parameters
f :: Integer -> Integer -> Integer
f x y = x + y

{- Note the type declaration.
The infix operator  “->” has a higher precedence with the right side.
That is, “a -> b -> c” means “a -> (b -> c)”,
so “Integer -> Integer -> Integer” means “Integer -> (Integer -> Integer)”.
The type “a -> (b -> c)” practically means a function taking type a and
returns a function with type (b -> c).

In our case, “f” is a function that takes a Integer x and returns a function
of type Integer -> Integer, and this function is given y as argument.

The function of two parameters f(x,y) can be thought of as made of two
other functions of single parameter g(x) and h(x). For each particular
value a, g(a) returns a particular function h, such that h(b) == f(a,b).
That is, f(a,b) == g(a)(b).
This is why its type declaration is like a sequence.  -}

{- this two-step nature also means that you can give one argument to f
and get a intermediate function h.
This is called partial application of a function.
For example, we define a function addOne using our f(x,y). -}

Data Types

-- datatype

data Temp = Cold | Hot
data Season = Winter | Spring | Summer | Fall deriving Show
-- 'Show' is how you turn a value into a string for display
-- 'show Winter' will work in Hugs
-- 'show Hot' will give an error because we didn't give a way to turn
-- Cold and Hot values into a string.

mySeason :: Season
mySeason = Summer

-- type aliases
type Name = String
type Age = Integer

-- more complex types
data People = Person Name Age

-- example
author1 = Person "Shae Erisson" 33
author2 = Person "Cale Gibbard" 21
author3 = Person "Amir Livne Bar-On" 18

birthday (Person name age) = Person name (age + 1)

-- records
data Tuple = {person :: Person, favoriteSeason :: Season}

-- example
database = [Tuple {person = author1, favoriteSeason = Summer},
Tuple {person = author3, favoriteSeason = Fall}]

-- person (head database) is author1
-- favoriteSeason (database !! 1) is Fall

-- polymorphic (parameterized, recursive) datatype
data Tree a = Nil | Node (Tree a) a (Tree a) deriving Show

myTree :: Tree Int
myTree = Node Nil 1 Nil

myOtherTree :: Tree Season
myOtherTree = Node Nil Winter (Node Nil Summer Nil)

-- pattern matching
-- each time the function is called, each line is tried in turn,
-- the first matching left hand side gets to execute its right hand side
mylength []     = 0
mylength (x:xs) = 1 + mylength xs

-- the second line with the (x:xs) construct above means that if a list is passed to the function
-- the first item of the list is assigned to x, and the rest of the list is assigned to xs

-- you can try the mylength function above by typing this into hugs or ghci:
-- mylength [1,2,3]

-- more pattern matching
-- the underscore matches anything at all, but doesn't assign to anything
weather        :: Season -> Temp
weather Summer = Hot
weather _      = Cold

-- where clauses introduce definitions local to a function.
ackermann :: Integer -> Integer
ackermann n = ack n n  -- (Peter's variant of the Ackermann function)
where
ack 0 m = m+1
ack n 0 = ack (n-1) 1
ack n m = ack (n-1) (ack n (m-1))

-- Typeclasses let you define the same operations on different types
-- the operators equal to ( == ) and not equal to ( /= ) are in the typeclass Eq
instance Eq Temp where
Cold == Cold = True
Hot == Hot = True
_ == _ = False

-- Eq is a built-in typeclass for checking equality, let's define our own typeclass

-- this isn't a very useful typeclass, because it can't sensibly be defined for anything other than Char
-- (because vowels are only in the alphabet, there aren't vowels in numbers)
-- something like class XML would be more useful, and could be defined for every type
class CharExts a where
isVowel     :: a -> Bool
isConsonant :: a -> Bool

instance CharExts Char where
isVowel a     = elem a "aeiouAEIOU"
isConsonant a = elem a (filter (not . isVowel) ['A'..'Z'] ++ output left in -
['a'..'z'])

-- short demonstration of guards
-- each conditional expression is tried in turn
guard x | x == 0     = 4
| (x*x) < 64 = 5
| otherwise  = 6

-- guard 0 evaluates to 4
-- guard 1 evaluates to 5
-- guard 9 evaluates to 6
-- can you guess what guard -1 will be?

-- Lazy computation example
-- Evaluation will bounce back and forth between the two infinite lists computing each element.
odds = 1 : map (+1) evens
evens = map (+1) odds
2005-10