
add x y = x + y

add3 x y z = x + y + z


my_abs x = x, if x >= 0
         = -x, otherwise          || note '=' are aligned.

is_zero 0 = True
is_zero x = False                 || 'x' will match anything.


my_and True x = x
my_and False x = False


car (x:xs) = x
cdr (x:xs) = xs

length [] = 0                    || match empty list
length (x:xs) = 1 + length xs    || match non-empty list


sum_3tuple (x,y,z) = x+y+z

check_length (len,str) = len = length str


factorial 0 = 1
factorial (n+1) = (n+1) * factorial n


is_length_one [x] = True
is_length_one xs = False         || this is a "match all" pattern

is_one_two_three [1,2,3] = True
is_one_two_three xs = False

cadr (y:x:xs) = x

twice_reversed list = rev ++ rev
                      where rev = reverse list

|| make forward-forward-reverse-reverse... list
ffrrffrr list = ffrr ++ ffrr
                where ffrr = ff ++ rev ++ rev 
                             where 
                                rev = reverse list
                                ff = list ++ list         


plus5 = add 5

foo 5 True 'a' = [1,2,3]
bar (2,'a') = add
baz 1 = foo

my_const x y = x

my_map2 f [] [] = []
my_map2 f (x:xs) (y:ys) = f x y : my_map2 f xs ys


twice f x = f (f x)
rev2 f x y = f y x


my_foldr op id = f
                 where
                    f [] = id
                    f (x:xs) = op x (f xs) 

my_foldl op id = f id
                 where 
                    f id [] = id
                    f id (x:xs) = f (op id x) xs

|| these are standard
my_sum = foldl (+) 0
my_product = foldl (*) 1
my_or = foldr (\/) False
my_and2 = foldr (&) True


my_if True x y = x
my_if False x y = y

ones = 1 : ones

factors n = filter is_factor [1..n]
	    where 
               is_factor k = n mod k = 0               

dullprimes = filter isprime [2..]
             where
                isprime p = (factors p = [1,p])

interestingprimes 
   = sieve [2..]
     where
        sieve (p:x) = p : sieve filtered
                      where 
                         filtered = filter not_multiple x
                         not_multiple n = n mod p > 0

|| hamming numbers

my_merge (x:a) (y:b) = x : my_merge a (y:b) , if x<y
                     = y : my_merge a b , if x=y
                     = y : my_merge (x:a) b , otherwise

ham = 1: my_merge ham2 (my_merge ham3 ham5)

ham2 = map (* 2) ham
ham3 = map (* 3) ham
ham5 = map (* 5) ham



weather ::= Rainy | Sunny | Cloudy | Snowy
month ::= Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec

forcast :: month->weather

forcast Aug = Sunny
forcast Jul = Sunny
forcast xxx = Rainy


shape ::= Circle num | Square num | Rectangle num num | Triangle num num

area :: shape->num
area (Circle r) = pi * r * r
area (Square width) = width * width
area (Rectangle width height) = width * height
area (Triangle base height) = base * height / 2.0

simplify :: shape->shape
simplify (Rectangle w w) = Square w
simplify s = s


tree * ::= EmptyTree | Node * (tree *) (tree *) 

t = Node 7 EmptyTree (Node 4 EmptyTree EmptyTree)

flatten EmptyTree = []
flatten (Node n left right) = flatten left ++ [n] ++ flatten right

filter' predicate list = [ x | x <- list; predicate x ]

map' f list = [ f x | x <- list ]

shapes = [Circle 5, Square 10, Rectangle 1 2, Circle 2]

radiuses list = [r | (Circle r) <- list]

abstype queue3 *
    with emptyqueue3 :: queue3 *
         isempty3 :: queue3 * -> bool
         head3 :: queue3 * -> *
         enqueue3 :: queue3 * -> * -> queue3 *
         dequeue3 :: queue3 * -> queue3 *
         
queue3 * == [*]
emptyqueue3 = []
isempty3 [] = True
isempty3 (a:x) = False           
head3 (a:x) = a
enqueue3 q a = q ++ [a]
dequeue3 (a:x) = x


abstype queue *
    with emptyqueue :: queue *
         isempty :: queue * -> bool
         head :: queue * -> *
         enqueue :: queue * -> * -> queue *
         dequeue :: queue * -> queue *

queue * == (num,[*],num,[*])            || (fl,front,rl,rear)
emptyqueue = (0,[],0,[])
isempty (0,[],0,[]) = True 
isempty q = False           
head (fl,(x:front),rl,rear) = x

enqueue (fl,front,rl,rear) x 
       = make_proper_queue (fl,front,rl+1,x:rear)

dequeue (fl,x:front,rl,rear) 
       = make_proper_queue (fl-1,front,rl,rear)

make_proper_queue (fl,front,rl,rear) 
       = (fl+rl, front ++ reverse rear,0,[]), if rl > fl
make_proper_queue q = q


q = foldl enqueue emptyqueue [1..100]


|| sequencing

fact' n = fact_tl 1 n
          where 
             fact_tl acc 0     = acc
             fact_tl acc (n+1) = fact_tl (acc * (n + 1)) n

fact n = fact_tl 1 n
         where 
            fact_tl acc 0     = acc
            fact_tl acc (n+1) = strict fact_tl (acc * (n + 1)) n
            strict f x = seq x (f x)

aFac 0 0 = 0
aFac 0 p = p
aFac (n+1) p = aFac n (p*(n+1)), if p=p

sum_range x x acc = acc
sum_range x y acc = sum_range (x+1) y (acc+x), if acc=acc









