{-- See Chapter 1, "Real World Haskell"
    http://book.realworldhaskell.org/read/index.html
    for information on running the Haskell interpretor ghci. 
    The chapter also covers much of the material from Chapter 5,
    "Concepts of Programming Languages" using Haskell as the example
    language.
--}

{- p. 104
In ML:
 -- <expression>;
 val it = <print_value> : <type>

In Haskell:
 Prelude> <expression>
 <print-value>

 Prelude> it
 <print-value>

 Prelude> :t it            -- :t <exp> asks for the type of <exp>
 <print-value> :: <type>   -- In Haskell, '::' is read "has type"
-}

{- p. 104, Second ML example 
 -- (5+3) -2;
 val it = 6 : int
 -- it + 3;
 val it = 9 : int
 -- if true then 1 else 5;
 val it = 1 : int
 -- (5 = 4);
 val it = false : bool

Equivalent Haskell
 Prelude> (5+3) - 2
 6
 Prelude> it + 3
 9
 Prelude> if True then 1 else 5
 1
 Prelude> (5 == 4)
 False
-}

{- p. 105, First ML Code fragment
 if true then 3 else false;

Equivalent Haskell
 if True then 3 else False

Results in:
    No instance for (Num Bool)
      arising from the literal `3' at <interactive>:1:13
    Possible fix: add an instance declaration for (Num Bool)
    In the expression: if True then 3 else False
    In the definition of `it': it = if True then 3 else False
The type checker is pointing out that the two branches of the if-statement
are not comparable.  We'll be able to understand the error message better
after the lecture on Type Classes.
-}

{- p. 105
 ML Declaration
 -- val <identifier> = <expression>;
 val <identifier> = <print_value> : <type>

Equivalent Haskell
 Prelude> let <identifier> = <expression>
 Prelude> <identifier>
 <print_value>
 Prelude>:t it     -- Ask for type of 'it'; equivalent to :t <identifier> 
 it :: <type>
-}

{- p. 105
ML Sample code
 -- val x = 7+2;
 val x = 9 : int
 -- val y = x + 3;
 val y = 12 : int
 -- val z = x*y - (x div y);
 val z = 108 : int

Equivalent Haskell
 Prelude> let x = 7 + 2
 Prelude> x
 9
 Prelude> let y = x + 3
 Prelude> y
 12
 Prelude> let z = x*y - (x `div` y) -- `div` makes div an infix operation.
 Prelude> z
 108
-}

{- p. 106
ML function declaration:
 -- fun <identifier> <arguments> = <expression>
 val <identifier> = fn <arg_type> -> <result_type>

Equivalent Haskell
 Prelude> let <identifier> <arguments> = <expression>
 Prelude> :t <identifier>
 <identifier> :: <function-type>
-}

{- p. 106
Example ML function declaration
 -- fun f(x) = x + 5;
 val f = fn : int -> int

Equivalent Haskell function declaration
 Prelude> let f x = x + 5
 Prelude> :t f                        -- what is the type of f?
 f :: forall a. (Num a) => a -> a     
 -- this type means: "for any type 'a' such that 'a' is "Numeric", f takes
 -- an argument of type 'a' and returns a value of the same time 'a'.
 -- For example, type 'a' could be Int or Integer or Float, etc.
 -- A "Numeric" type is required to support the opeations of +,-,*,
 -- negation, absolute value, sign, etc.
 -- We'll explore this kind of type in more detail on the lecture on
 -- type classes.  
-}

{- p. 106
ML function declaration via val declaration
 -- val f = fn x => x + 5;
 val f = fn : int -> int

Equivalent Haskell
 Prelude> let f = \x -> x + 5
 Prelude>:t f
 f :: Integer -> Integer
-- In this case, the Haskell interpretor ghci picked the type Integer
-- for the type variable 'a' from the previous example and simplified
-- the type accordingly.
-}

{- p. 107
 ML Unit Value/Type 
 -- () : Unit
 Haskell Unit Value/Type
 Prelude> () :: ()  
 -- Haskell uses the notation '()' to denote *both* the unit value *and*
 -- the unit type, i.e., both ML's '()' for the unit value and Unit for 
 -- the unit type.
-}

{- p. 107 
 ML Boolean Values/Type
 -- true : bool
 -- false : bool
 -- if e1 then e2 else e3  (* assuming e1, e2, and e3 are expressions *)

 Equivalent Haskell
 Prelude>True :: Bool    -- Types in Haskell are capitalized
 Prelude>False :: Bool   -- Data constructors in Haskell are capitalized
 Prelude> if e1 then e2 else e3 -- assuming e1,e2, and e3 are expressions
-}

{- p. 108
Conditionals in Haskell are required to have both 'then' and 'else' branches 
just as i ML 
-}

{- p. 108
 ML Boolean operations
 -- fun equiv(x,y) = (x andalso y) orelse ((not x) andalso (not y));
 val equiv = fn : bool * bool -> bool
 -- equiv(true,false)
 val it = false : bool

Equivalent Haskell
  Prelude>let equiv (x,y) = (x && y) || ((not x)  && (not y))
  Prelude>equiv (True, False)
  False
-}

{- p. 108
 ML Integers
 0,1,2,...,-1,-2,...:int
 +,-,*,div : int * int -> int

 Equivalent Haskell
 0,1,2,...,-1,-2,...:Integer
 The operations +,-, and * are infix binary operators that work over any
 type that is a "Num," which we discussd earlier. 
 The type Integer is one such type. 
 The notation (op) converts an infix operator to a regular function.
Prelude>:t (+)
(+) :: forall a. (Num a) => a -> a -> a
Prelude> :t (-)
(-) :: forall a. (Num a) => a -> a -> a
Prelude> :t (*)
(*) :: forall a. (Num a) => a -> a -> a
 The operation div is a regular binary function that works over any type that
 is "Integral." Types are "Integral" if they support the operations quotient 
 (quot), remainder (rem), division (div), mod, etc.
Prelude> :t div
div :: forall a. (Integral a) => a -> a -> a
 The notation `div` converts the function div into an infix operator.

ML function quotient
 -- fun quotient (x,y) = x div y;
 val quotient = fn : int * int -> int

Equivalent Haskell function
Prelude> let quotient (x,y) = x `div` y
Prelude> :t quotient
quotient :: forall t. (Integral t) => (t, t) -> t
-}

{- p. 109
 ML Strings
 -- "Willian Jefferson Clinton" : string
 -- "Borris Yeltsin" : string

 Equivalent Haskell
 Prelude>"Willian Jefferson Clinton" :: String
 Prelude>"Borris Yeltsin" :: String
 -- In Haskell, the type String is equal to a list of Char, written [Char]

 ML String Concatentation
 -- "Chelsey" ^ " " ^ "Clinton";
 val it = "Chelsey Clinton" : string

 Haskell String Concatenation
 Prelude>"Chelsey" ++ " " ++ "Clinton"
 "Chelsey Clinton"
-}

{- p. 109, Real
 In ML,
 1.0, 2.0, 3.14159, 4.44444, ... : real
 -- 3+4;
 val it = 7 : int
 -- 4.0 + 5.1;
 val it = 9.1 : real
 -- 4 + 5.1;
 stdIn:1.1-1.6 Error: operator and operand don't agree [literal]
 operator domain: int * int
 operand:     int * real

 Equivalent Haskell
  1.0, 2.0, 3.14159, 4.4444,... : Float -- Among other types...
  Prelude> 3+4
  7
  Prelude> 4.0 + 5.1
  9.1
  Prelude> 4 + 5.1
  9.1
 Because of the way Haskell supports overloading (using the Num, Integral, etc.
 predicates over types that we've been seeing in the types of numeric 
 operations), the Haskell type system is able to type check adding an 
 Integer and a Float.
-}

{- p. 110, Tuples
In ML:
  -- (3,4);
  val (3,4) : int * int
  -- (4,5,true);
  val (4,5,true) : int * int * bool
  -- ("Bob", "Carol", "Ted", "Alice") ;
  val ("Bob", "Carol", "Ted", "Alice") : string * string * string * string

In Haskell
  Prelude> (3,4)
  (3,4)
  Prelude> :t it   -- Remember, :t asks for the type of the following expression
  it :: (Integer, Integer)  -- Remember, 'it' is the last value entered.
  Prelude> (4,5,True)
  (4,5,True)
  Prelude> :t it
  it :: (Integer, Integer, Bool)
  Prelude> ("Bob", "Carol", "Ted", "Alice")
  ("Bob","Carol","Ted","Alice")
  Prelude> :t it
  it :: ([Char], [Char], [Char], [Char])  -- Remember, String = [Char]
-}

{- p. 110, Selected components from tuples
In ML:
  -- #2(3,4);
  val it = 4 : int
  -- #3("John", "Paul", "George", "Ringo");
  val it = "George" : string

In Haskell
  Prelude> fst (2,3)
  2
  Prelude> snd (2,3)
  3

Haskell does not have short-hands for acessing later elements of a tuple.
Instead, it uses *pattern-matching* to access these elements, which we will
see in a little bit...

If we say 
  Prelude>:set +t
ghci will output more type information:
  Prelude>3
  3
  Prelude>:set +t
  Prelude>3
  it :: Integer
If we say
  Prelude>:unset +t
ghci goes back to the terse output mode.
-}

{- p. 110, Records
In ML
  -- {First_name = "Donald", Last_name="Knuth"};
  val it = {First_name = "Donald", Last_name="Knuth"} : 
           {First_name : string, Last_name : string }
-}
-- In Haskell:
data Person = Person {first_name :: String, 
                      last_name  :: String } deriving (Show)
dk = Person{first_name = "Donald", last_name = "Knuth"}
-- Haskell does not have support for anonymous records like ML does
-- (as illustrated by the example above).
-- Instead, we have to declare the type of the record 
-- (in the line data... above)
-- We'll see more declarations of this form shortly.
-- The "deriving (Show)" is related to Haskell's support for overloading.
-- It directs the compiler to generate printing code to display values
-- of type "Person" by using the printing code for Strings.
-- With this declaration, when we ask the intereptor for the value of dk,
-- we get:
--
-- *Main> dk
-- Person {first_name = "Donald", last_name = "Knuth"}
-- it :: Person
-- *Main> 
--
-- Note that the change from "Prelude" to "Main" indicates this code
-- was loaded from a file into the interpretor rather than being
-- entered directly into the command-line.
-- For more information on using ghci, see Chapter 1 of "Real-World Haskell":
--      http://book.realworldhaskell.org/read/getting-started.html


{- Record selection
In ML:
  -- #First_name({First_name="Donald", Last_name="Knuth"});
  val it = "Donald" : string

In Haskell:
  *Main> first_name dk
  "Donald"
  it :: String
-- Assuming we have previously defined dk
-}

{- p. 111, Lists
In ML
 -- [1,2,3,4];
 val it = [1,2,3,4] : int list
 -- [true, false];
 val it = [true, false] : bool list
 -- ["red", "yellow", "blue"];
 val it = ["red", "yellow", "blue"] : string list
 -- [fn x => x + 1, fn x => x+2] 
 val it = [fn, fn] : (int -> int) list

In Haskell
 Prelude> [1,2,3,4]
 it :: [Integer]    
 Prelude> [True,False]
 [True,False]
 it :: [Bool]
 Prelude> ["red", "yellow", "blue"]
 ["red","yellow","blue"]
 it :: [[Char]]       -- which is the same as [String]
 Prelude>let fns = [\x -> x+1, \x -> x + 2]
 fns :: [Integer -> Integer]
 -- Entering the list of functions directly produces:
 Prelude>[\x -> x+1, \x -> x + 2]

<interactive>:1:0:
    No instance for (Show (a -> a))
      arising from a use of `print' at <interactive>:1:0-23
    Possible fix: add an instance declaration for (Show (a -> a))
    In the expression: print it
    In a stmt of a 'do' expression: print it
-- Which means ghci does not know how to print function values.
-- It does not simply print "fn" as ML does.
-}

{-- Cons
 In ML
  -- 3 :: nil;
  val it = [3] : int list
  -- 4 :: 5 :: it;
  val it = [4,5,3] : int list

 In Haskell
  Prelude> 3 : []
  [3]
  it :: [Integer]
  Prelude> 4 : 5 : it
  [4,5,3]
  it :: [Integer]
--}

{-- p. 112, Value Declarations
In ML,
  -- val t = (1,2,3)
  val t = (1,2,3) : int * int * int
  -- val (x,y,z) = t;
  val x = 1 : int
  val y = 2 : int 
  val z = 3 : int

In Haskell
  Prelude>let t = (1,2,3)
  t :: (Integer, Integer, Integer)
  Prelude> let (x,y,z) = t
  x :: Integer
  y :: Integer
  z :: Integer
  Prelude>x
  1
  it :: Integer
  etc.
--}

{-- p. 113, Function Declarations
In ML
  -- fun f(x,y) = x+y;
In Haskell
  Prelude>let f(x,y) = x + y

In ML
  -- fun length(nil) = 0
       | length(x::xs) = 1 + length(xs);
  val length = fn : 'a list -> int
  -- length ["a","b","c","d"];
  val it = 4 : int
--}
-- In Haskell
length' [] = 0
length' (x:xs) = 1 + length' xs
-- The name length is defined in the standard prelude for Haskell,
-- so we need to choose a different name here.
{-
Main*> length' ["a","b","c","d"]
4
it :: Integer
-}

{-- p. 114, Anonymous functions
In ML
  -- fn (x,y) => x + y;
  val it = fn : int * int -> int
In Haskell
   Prelude>let f = \x y-> x + y
   f :: Integer -> Integer -> Integer
If we just type 
   Prelude>\x y-> x + y
ghci returns an error message saying it doesn't know how to print a function,
as we saw previously.
-}

{-- p. 114, other pattern matching
In ML
 -- fun f(x,(y,z)) = y;
 val f = fn : 'a * ('b * 'c) => 'b
 -- fun g(x::y::z) = x :: z;
 val g = fn : 'a list -> 'a list
 -- fun h{a=x,b=y,c=z} = {d=y,e=z};
 val h = fn : {a:'a, b:'b, c:'c} -> {d:'b, e:'c}

In Haskell
  Prelude>let f (x, (y,z)) = y
  f :: forall t t1 t2. (t, (t1, t2)) -> t1
which means the same thing as the ML type: 'a * ('b * 'c) => 'b

  Prelude> let g (x:y:z) = x:z
  g :: forall t. [t] -> [t]
which means the same thing as the ML type: 'a list -> 'a list
--}
--  As we saw before, Haskell requres records to be declared before 
--  they are used, so we can't transliterate the third example as before.
--  We can still deconstruct records using pattern matching:
h (Person first_name last_name) = first_name ++ " " ++ last_name
-- See Section "Record Syntax", Chapter 4, "Real World Haskell" for more 
-- information: 
-- http://book.realworldhaskell.org/read/defining-types-streamlining-functions.html

{-- p. 114, pattern-matching order
In ML
  fun f(x,0) = x
    | f(0,y) = y
    | f(x,y) = x+y;
-}
--In Haskell, the same ordering applies:
f (x,0) = "First clause"
f (0,y) = "Second clause"
f (x,y) = "Third clause"

{-- p. 115, duplicate patterns
In ML,
 -- fun eq(x,x) = true
      | eq(x,y) = false
 stdIn:24.5-25.20 Error: duplicate variable in pattern(s)

In Haskell
eq(x,x) = True
eq(x,y) = False
/Users/kfisher/Teaching/cs242/Code/chapter5.hs:512:3:
    Conflicting definitions for `x'
    In the definition of `eq'
Failed, modules loaded: none.
--}

{-- p. 115, Datatypes
In ML
  -- datatype color = Red | Blue | Green;
  datatype color = Blue | Green | Red
--}

--In Haskell
data Color = Red | Blue | Green

{- 
In ML
 -- datatype student = BS of name | MS of name*school | PhD of name*faculty;
 -- fun name(BS(n)) = n
      | name(MS(n,s)) = n
      | name(PhD(n,f)) = n;
    val name = fn : student -> name
-}

--In Haskell
type Name = String
type School = String
type Faculty = String
data Student = BS Name | MS (Name,School) | PhD (Name,Faculty)

name (BS n) = n
name (MS (n,s)) = n
name (PhD (n,f)) = n

-- *Main>:t name
-- name :: Student -> Name

{-- p. 117, Tree example
In ML,
 datatype tree = LEAF of int | Node of (tree * tree);
 -- fun inTree(x,LEAF(y)) = x = y
      | inTree(x,NODE(y,z)) = inTree(x,y) orelse inTree(x,z);
 val inTree = fn : int * tree -> bool
--}
 
-- In Haskell
data Tree = Leaf Integer | Node (Tree,Tree)
inTree (x,Leaf y) = x == y
inTree (x,Node (y,z)) = inTree(x,y) || inTree(x,z)

-- *Main> :t inTree
-- inTree :: (Integer, Tree) -> Bool
