{- ghci command
     Prelude> :set +t 
   asks for more type information.
-}

import List
import Test.QuickCheck

l = [1,2,3]
r = foldl (\accumulator i -> i + accumulator) 0 l

true = True
false = False

ifExpression = if true then 10 else 13

anInt = 2
anIntExpression = 2 * 4

aString = "Ron Weasley"

aFloat = 2.2

aTuple = (4,5,"Griffendor")

nilList = []

anIntList = 1 : [2,3,4]

myTuple = ("Flitwick", "Snape")
(x,y) = myTuple
myList = [1,2,3,4]
z:zs = myList

data Person = Person {firstName :: String, lastName :: String}
hg = Person {firstName = "Hermione", lastName = "Granger"}


localDecl = let x = 2+3 in 4 

anonymousFunction = \x -> x + 1

f(x,y) = x + y
myLength [] = 0
myLength (x:xs) = 1 + myLength xs

myMap f [] = []
myMap f (x:xs) = f x : myMap f xs

applyMap = myMap (\x -> x + 1) [1,2,3]

myReverse [] = []
myReverse (x:xs) =  (reverse xs) ++ [x] 

append([], ys) = ys
append(x:xs, ys) = x : append(xs, ys)

eReverse xs =
    let rev ( [], z ) = z
        rev ( y:ys, z ) = rev( ys, y:z )
    in rev( xs, [] )

data Color = Red | Yellow | Blue

data Atom = Atom String | Number Int

data List = Nil | Cons  (Atom,List)

data Tree = Leaf Int | Node (Int, Tree, Tree)
            deriving Show

aTree = Node(4, Node(3, Leaf 1, Leaf 2),
                Node(5, Leaf 6, Leaf 7))         

tsum (Leaf n) = n
tsum (Node(n,t1,t2)) = n + tsum(t1) + tsum(t2)

data Exp = Var Int | Const Int | Plus (Exp, Exp)
           deriving Show

exampleExp =  Plus(Plus(Var 1, Const 3), Var 2)

exampleCase = case exampleExp of
               Var n ->  n
               Const n -> n
               Plus(e1,e2) -> 0

exampleExp2 = Plus(Const 3, Const 2)
exampleExp3 = Plus(Var 1, Plus(Const 2, Const 3))

ev ( Var n) = Var n
ev ( Const n ) = Const n
ev ( Plus ( e1,e2 ) ) = 
     case ev e1 of
          Var n -> Plus( Var n, ev e2)      
          Const n -> case ev e2 of  
                              Var m -> Plus( Const n, Var m)      
                              Const m -> Const (n+m)                         
                              Plus(e3,e4) -> Plus ( Const n, Plus ( e3, e4 ))   
          Plus(e3, e4) -> Plus( Plus ( e3, e4 ), ev e2)

main = return "This file contains example code from the introductory lecture on Haskell."

type TS =  [Int] -- Test Reverse function at this type.
prop_RevRev :: TS -> Bool
prop_RevRev l = eReverse (eReverse l) == l

isSubString :: String -> String -> Bool
x `isSubString` s = or [ x `isPrefixOf` t
                         | t <- tails s ]

myTails :: String -> [String]
-- All suffixes of s
myTails []     = [[]]
myTails (x:xs) = (x:xs) : myTails xs

myOr :: [Bool] -> Bool
-- (or bs) returns True if any of the bs is True
myOr []     = False
myOr (b:bs) = b || myOr bs

 
