This file defines Stack module
> module Stack where
type keyword can be used to create type synonyms:
type MyInt = Int
makes MyInt an alias of built-in type Int. MyInt can be used in place of Int. MyInt is called a type constructor, just like Int.
> type Stack a = [a]
defines a type synonym, Stack. Stack is synonym of [a], which is a list of a's. a is a type variable. It can be instantiated with different types:
So, Stack is a type constructor that takes 1 parameter, a. Once it has taken the parameter, it can construct a concrete type, e.g. a list of Int.
Types and type constructors must start with an uppercase letter, unlike normal functions.
One can annotate type of a function:
functionName :: Type
tells the compiler that the function functionName has type Type. :: is part of type annotation syntax. a :: B says, "a has type B".
> isEmpty :: Stack a -> Bool
So, isEmpty has type Stack a -> Bool. a -> b means it is a function whose domain is type a and range is type b (a function that takes a value of type a and returns a value of type b). Hence, isEmpty is a function that takes Stack a (a list of a's) and returns Bool (boolean).
> isEmpty = null
After type annotation of a function, definition of the function must follow. So, isEmpty is same as null, which is a Haskell function that returns True if the list is empty, False otherwise:
ghci> :t null null :: [a] -> Bool ghci> null "" True ghci> null [] True ghci> null [1] False
:t expr is GHCi command that prints type of expr.
> pop :: Stack a -> (a, Stack a)
> pop (x:xs) = (x, xs)
defines function pop that takes a list of a's and returns a pair of a and a list of a's.
(a, b) means a pair of a value of type a and a value of type b:
ghci> (1, 1) :: (Int, Float) (1, 1.0)
You can also annotate type of an expression with :: .
Definition of pop uses pattern. A pattern can be a literal or something that starts with (or includes) a function (normal function, type constructor, data constructor, operator). : in (x:xs) is a data constructor for list types:
ghci> :t (:) (:) :: a -> [a] -> [a]
A data constructor is a function that starts with : and continues with special characters, or a function that starts with an uppercase letter and continues with normal function name. For example, :->, :===-?, Hello, He''ll__o are data constructors.
(x:xs) is same as ((:) x xs). pop (x:xs) matches function calls like:
pop [1,2,3] pop "abc"
because:
pop [1,2,3] ==> 1 : [2,3] ==> (1, [2,3])
| +----- xs ------|----+
+----------- x ------+
pop "abc" ==> 'a' : "bc" ==> ('a', "bc")
| +------ xs -------|----+
+------------ x -------+
> push :: a -> Stack a -> Stack a
> push v s = v : s
push matches calls like:
push 1 [2,3] ==> [1,2,3]
| +------- s ------|--+
+----------- v ------+
push 'a' "bc" ==> "abc"
| +------ s ------|+
+---------- v ------+
ghci> :l Stack
ghci> pop "abc"
('a',"bc")
ghci> push 'a' "bc"
"abc"
ghci> pop []
*** Exception: Stack.lhs:87:2-21: Non-exhaustive patterns in function pop
pop [] throws an exception because pop is defined only on (x:xs), a list of at least one element. So, [] won't match x:xs and causes an exception.