defining functions

Haskell is a functional programming language. This basically means functions are first-class citizens. Let’s look at how to define a function.

add x y = x + y

add 1 2
3

functions are partial

In haskell, functions can be partially applied (applied with less arguments than defined)

add1 = add 1

add1 2
3

If we apply

1
add
with only one argument
1
1
, then we get a new function
1
add1
which takes one argument.

infix and prefix

In haskell, infix functions (i.e. operators in other languages) and prefix functions are treated alike. They can be transformed into each other using

1
()
and
1
` `

-- infix -> prefix
1 + 2
3
(+) 1 2
3

-- prefix -> infix
myadd x y = x + y
1 `add` 2
3

let

The

1
let
statement provides syntactic sugar for
1
"defining variables"
.

let x = 1
    y = 2
    add x y = x + y
in 1 + (add x y)
4

I put quotes around “defining variables” because x and y are not variables in other languages’ sense. Instead, they are just bindings local to the statement, which is somewhat unique to haskell. The let statement can also define functions.

closures/anonymous functions/lambdas

-- the follwing are equivalent:
add x y = x + y
add = \x y -> x + y

-- the follwing are equivalent:
add 1
\x add 1 x

lazy evaluation

-- the cycle function
take 10 (cycle [1,2,3])
[1,2,3,1,2,3,1,2,3,1]

-- one way to define the cycle function
cycle x = x ++ cycle x

1
cycle [1,2,3]
generates an infinite list
1
1,2,3,1,2,3,1,2,3,...
. Because Haskell is lazy, applying
1
take 10
to that list actually yields an finite list ``.

type, type class

a type class is like a Java interface a type, a type is like a concrete Java class implementing an interface,

We use

1
data
to define a type.

data Point = Point Int Int deriving Show

Point 1 2

The

1
Show
typeclass defines a
1
show
function which is used to print a data type. We can redefine this function as follows:

data Point = Point Int Int
instance Show Point where
    show (Point x y) = (show x) ++ "," ++ (show y)

type constructor

data Maybe a = Nothing | Just a

We call

1
Maybe
a type constructor. Depending on the type of
1
a
, this constructor can end up creating a Maybe Int, Maybe Car, or Nothing.

functors

The

1
Maybe
is an instance of
1
Functor
type class. A
1
Functor
is simply something that you can map on.

class Functor f where
    fmap :: (a -> b) -> f a -> f b

-- lists are instances of functors
instance Functor [] where
    fmap = map

-- maybe's are instances of functors
instance Functor Maybe where
    fmap f (Just x) = Just (f x)
    fmap f Nothing = Nothing

fmap inc (Just 1)

It’s easy (or not so easy) to see that

1
Lists
and
1
Maybe's
are instances of
1
Functors
.

pattern matching and erlang-like case statements

As seen above, pattern matching can be used in function arguments. It can also be used in

1
case
statements and
1
let
statements.

let (Point x y) = (Point 1 2) in
    x + y

head' :: [a] -> a
head' xs = case xs of [] -> error "No head for empty lists!"
                      (x:_) -> x

:kind :info :type

  • 1
    
    :kind
    
    shows type information on types and type classes
  • 1
    
    :info
    
    shows detailed information on types and type classes.
  • 1
    
    :type
    
    shows type for instances of types, and type classes for types.