-- Time-stamp: <Thu Nov 29 2001 11:38:12 Stardate: [-30]7627.42 hwloidl>
-- 
-- Simple Haskell functions demonstrating basics of Haskell.
-- Used for the course 12.4PL1 "Language and Design", term 1, 2001/02.
--
-- The structure in this module corresponds to the structure in the
-- lecture.
--
-- Use the ghci as Haskell interpreter.
-- It's available from: /net/azdak/dsg/local/i386-unknown-linux/bin
-- Documentation: http://haskell.cs.yale.edu/ghc/documentation.html
---------------------------------------------------------------------------

module Demos_1 where

-- I. Algebraic data-types

data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun
           deriving (Read,Show,Eq,Ord)

data MyList alpha = Nil | alpha :^ (MyList alpha)

-- Pattern matching over this new data type is very useful:
next Mon = Tue
next Tue = Wed
next Wed = Thu
next Thu = Fri
next Fri = Sat
next Sat = Sun
next Sun = Mon

-- Parametric polymorphism means that you can define functions that work for any
-- instance of \texttt{alpha}:
my_length :: MyList alpha -> Int
my_length Nil     = 0
my_length (x:^xs) = 1+(my_length xs)

-- Pattern matching
sqs1 []    = []
sqs1 (h:t) = h*h : sqs1 t

sqs2 xs = if (null xs) then []
                       else let 
                              h = head xs
                              t = tail xs
                            in 
                              h*h : sqs2 t

-- Guarded patterns
more0 [] = 0 
more0 (h:t) | h>0 = 1+more0 t
            | otherwise = more0 t

-- squares-even as a list comprehension
sqs1_even xs = [x*x | x <- xs, even x]

---------------------------------------------------------------------------

-- II. Higher-order functions

-- The predefined higher-order function map applies a function to all
-- elements of a list, i.e. map f [1,2,3] = [f 1, f 2, f 3]

-- squares-even with higher-order functions
sqs2_even = map (\ x -> x*x) . filter even

-- using a map
sqs4 xs = map square xs
          where square x = x*x

-- using a map and an anonymous function
sqs5 xs = map (\ x -> x*x) xs

-- using a map and a section
sqs6 xs = map (^2) xs

-- same as above, but shorter
sqs7 = map (^2)

---------------------------------------------------------------------------

-- IV. Lazy Evaluation

-- this functions generates an infinite list of values, starting with x
-- the same as typing: [x..] in the interpreter
my_enumFrom :: Int -> [Int]
my_enumFrom n = n:(my_enumFrom (n+1))

-- Test this by trying e.g. 
--  > (my_enumFrom 1) !! 2
-- or
--  > take 10 (my_enumFrom 1)

my_enumFromTo :: Int -> Int -> [Int]
my_enumFromTo m n | m<=n       = m:(my_enumFromTo (m+1)  n)
                  | otherwise  = []

-- Test this by trying e.g. 
--  > (my_enumFromTo 1 10) !! 2
-- or
--  > take 10 (my_enumFromTo 1 10)

-- the following variants of the above functions demonstrate the
-- use of type classes and overloading in Haskell
my_enumFrom' :: (Enum a) => a -> [a]
my_enumFrom' n = n:(my_enumFrom' (succ n))

-- this is a more general version using type classes and overloading 
-- so that we can use the function on many different types, namely
-- all types that have a '<' function (therefore we need Ord) and
-- all types that have a 'succ' function (therefore we need Enum)
my_enumFromTo' :: (Ord a, Enum a) => a -> a -> [a]
my_enumFromTo' m n | m<=n       = m:(my_enumFromTo' (succ m)  n)
                   | otherwise  = []


