{-- -- TalTech ITI0212 -- -- Functional Programming -- -- week 2, 2022-02-02 -- -- Inductive Types and Recursive Functions --} module Lecture2 -- Idris comes with a few built-in types, -- but also a powerful system for defining new types. -- specification of an inductive data type: data Bool' : Type where -- list of element constructors: False' : Bool' True' : Bool' -- This type is already in the standard library -- where it is called 'Bool'. -- To define a function from a boolean -- we want to know which boolean we are given. -- We can do this using a case expression: not_c : Bool -> Bool not_c b = case b of False => True True => False -- Case-analysing a function argument is very common. -- There is a special syntax for this task called -- definition by pattern-matching: not_m : Bool -> Bool not_m False = True not_m True = False -- Boolean negation is also in the standard library, -- where it is called 'not'. -- Let's write boolean conjunction. and : Bool -> Bool -> Bool and False False = False and False True = False and True False = False and True True = True -- Because of first-match semantics -- we can use clause order and unalyzed arguments -- to streamline function definitions. and' : Bool -> Bool -> Bool and' True True = True and' _ _ = False -- Boolean conjunction* is in the standard library -- where it is called '(&&)'. -- The type Bool has exactly two elements. -- Let's write a type that has exactly one element. data Unit' : Type where MkUnit' : Unit' -- The Unit type is also in the standard library. -- Warning: syntactic sugar () : () -- Functions from the Unit type have only one case: tt : Unit -> Bool tt () = True -- Functions to the Unit type have only one place to go: erase : Bool -> Unit erase x = () -- We can also write a type that has exactly zero elements. data Void' : Type where -- no constructors! -- The Void type is also in the standard library. -- Functions from the Void type have no cases: triv : Void -> Bool triv x impossible -- Functions to the Void type have no place to go: stuck : Bool -> Void stuck b = stuck (not b) -- never returns -- Strange loops: impossible_loop : Void -> Void impossible_loop x impossible -- identity_loop : Void -> Void identity_loop x = x -- Soon we will learn how to specify types -- with exactly n elements for any n. -- For that we will need the type of natural numbers: data Nat' : Type where -- zero is a natural number: Z' : Nat' -- the successor of a natural number is a natural number: S' : Nat' -> Nat' -- This type is in the standard library -- and includes syntactic sugar for numeric literals. lucky : Nat lucky = 7 -- We can define natural number addition -- by recursuion on the first argument: add : Nat -> Nat -> Nat add Z n = n add (S m) n = S (add m n) {-- evaluation semantics: add 2 n | desugar 2 ~> add (S (S Z)) n | c.2: m := S Z ; n := n ~> S (add (S Z) n) | c.2: m := Z ; n := n ~> S (S (add Z n)) | c.1: ; n := n ~> S (S n) --} -- If we don't immediately see what to do -- then we can use a let expression -- to capture the result of a recursive call: add' : Nat -> Nat -> Nat add' Z n = n add' (S m) n = let m_plus_n : Nat m_plus_n = add' m n in S m_plus_n -- Nat addition is in the standard libray as 'plus'. -- You can also use the overloaded operator '(+)'. public export -- the evenness predicate for natural numbers: even : Nat -> Bool -- zero is even: even Z = True -- one is not even: even (S Z) = False -- 2 + n is even just in case n is even even (S (S n)) = even n -- The equality predicate for natural numbers: nat_eq : Nat -> Nat -> Bool nat_eq Z Z = True nat_eq (S m) (S n) = nat_eq m n nat_eq _ _ = False -- The different constructors of an inductive type -- record the different ways of forming its elements: data Shape : Type where Circle : (radius : Double) -> Shape Rectangle : (width : Double) -> (height : Double) -> Shape IsocTriangle : (base : Double) -> (height : Double) -> Shape -- Functions from inductive types can act differently -- depending on which constructor was used: area : Shape -> Double area (Circle radius) = pi * radius * radius area (Rectangle width height) = width * height area (IsocTriangle base height) = base * height / 2