-- CPSC 312 - 2024 - Types in Haskell
module Types where

-- To run it, try:
-- ghci
-- :load Types

-- Try in ghci
-- :type True
-- :type not

answ :: Integer
answ = 42

square :: Double -> Double      -- type declaration
square x = x*x

-- Haskell Can Infer Types
fourth x = square (square x)

-- Try:
-- :type fourth


-- functions with multiple arguments:
foo :: Double -> Double -> Double
foo x y = 1000*x+y

foog x y = 1000*x+y



-- mynot is an implementation of not
mynot True = False
mynot False = True

-- xor1 is exclusive-or
xor1 a b = (a && not b) || (not a && b)

-- xor is exclusive-or
xor2 x y = (x || y) && (not x || not y)

-- myxor is exclusive-or
xor True  x = not x
xor False x = x

-- myif condition then_exp else_exp is an implementaion of if-then-else
myif True  then_exp else_exp = then_exp 
myif False then_exp else_exp = else_exp

-- fac n is the factorial of n
fac :: Integer -> Integer
fac n = myif (n==0) 1 (n*fac (n-1))

-- gfac n is a generalied factorial that also works for reals
gfac n = myif (n<=0) 1 (n*gfac (n-1))


-- Integers and Reals cannot be mixed!

-- 100 / 7
-- div 100 7
-- div 100.0 7
-- 100 `div` 7
-- (/) 100 7
-- :type div 100 7
-- :type 1.5
-- (div 100 7) + 1.5
-- :type (div 100 7) + 1.5
-- fromIntegral (div 100 7) + 1.5

average ns = sum ns `div` length ns
-- sum sums the elements of a list. try:
-- average [1,2,3,4,5,6]

-- myave ns = sum ns / length ns

-- myave ns = sum ns / fromIntegral (length ns)


------- MORE INFIX EXAMPLES ------
plus1 x = x+1
plus x y= x+y
pls(x,y) = x+y
-- How can pls be called?

ff f x = f (f x)

-- Try:
-- ff plus1 5
-- ff (plus 6) 1
-- ff (+ 6) 1
-- ff (* 10) 2

fourthnew = ff square

--- Infix operators
x ++++ y = 1000*x+y

-- 7 ++++ 3
-- (++++) 7 3
-- (7 ++++) 3
-- ((++++) 7) 3
-- (++++ 7) 3
-- ff (++++ 7) 4
-- ff (7 ++++) 4
-- ff ((++++) 7) 4
-- (* 7) `ff` 2

-- mymax x y returns the maximum of x and y
mymax x y
   | x>y = x
   | otherwise = y

-- notmymax x y returns the maximum of x and y
notmymax x y
   | x>y = x
   | x<y = y
--what does this work for? What does this not work for?

-- max3 x y z returns the maximun of x y z
max3 x y z
 | x >= y && x>= z = x
 | y >= z          = y
 | otherwise       = z

-- max3a x y z returns the maximun of x y z
max3a x y z = mymax x (mymax y z)

-- max3a x y z returns the maximun of x y z
max3b x y = mymax (mymax x y)

max3c x y z = mymax (mymax x y) z