{-- -- TalTech ITI0212 -- -- Functional Programming -- -- week 3, 2022-02-09 -- -- Parameterized Types and Generic Functions --} module Lecture3 {- Last time: inductive types and recursive functions Today's lecture --------------- Continuing the dive into Idris' type system: - Parametrized types (aka. generic types, parametric types, or types depending on types) and the kinds of functions involving them: - generic functions (aka. polymorphic functions, or terms depending on types) -} {- Recap -} -- The types we have seen so far have nullary type constructors -- In other words: Bool has no arguments, it is just directly a type -- :t Bool ;=> Prelude.Bool : Type data Bool' : Type where True' : Bool' False' : Bool' {- Preliminary explanation -} -- Parameterized types have type constructors with types such as: -- Type -> Type -- Type -> Type -> Type -- ... -- In short: parameterized types have type constructors with function -- types, where the arguments are types (terms of type Type) -- These are an important special case of dependent types: they depend -- on terms of type Type. We will see dependence on terms of other -- types later. {- Motivation: Lists -} -- Syntax: an (undefined) lowercase name in a type signature is a -- type-level variable or "type parameter" -- Heterogeneous list. A lowercase name stands for any type whatsoever data HList : Type where NilH : HList ConsH : a -> HList -> HList {- Lists containing terms of one type (a), for any type (a) -} -- We require a unary parametric type constructor: data List' : Type -> Type where Nil' : List' a Cons' : a -> List' a -> List' a -- Note: List' itself is not a type but returns a type when given any -- type. We can think of List' as defining an entire family of types, -- one for each type : Type. -- Idris' built in list type (List) has syntactic sugar -- Nil is [] -- Cons is :: -- and we can simply write [1,2,3] to stand for 1 :: 2 :: 3 :: [] {- generic length function -} length' : List a -> Nat length' [] = 0 length' (x :: xs) = 1 + length' xs {- generic concatenation function -} concat' : List a -> List a -> List a concat' [] ys = ys concat' (x :: xs) ys = x :: concat' xs ys -- syntax: (++) infix for concat. {- a parameterized type of Pairs -} data Pair' : Type -> Type -> Type where MkPair' : a -> b -> Pair' a b -- Return first member of pair fst' : Pair a b -> a fst' (x, y) = x -- Think: this is the only possible function with this type signature! -- Syntax: Idris' built-in MkPair has syntactic sugar (x,y) diag : a -> Pair a a -- Again, there is only one possible function with this type! Why? diag x = (x, x) {- Side note on explicitly bound implicit variables -} -- In Idris 2, we must explicitly bind an implicit variable -- if we wish for it to be in scope on the RHS type_of_list : {a : Type} -> List a -> Type type_of_list _ = a -- Intuition: an implicitly bound variable is something we expect -- Idris to infer for us, it is not something we have to provide -- explicitly, even if we explicitly bind it. -- e.g. type_of_list [1,2,3] ;=> Integer -- we only supply the non-implicit argument {- the parameterized type Maybe Intuition: adding an extra value to a type (e.g. to represent an error state) -} data Maybe' : Type -> Type where Nothing' : Maybe' a Just' : a -> Maybe' a -- The first element of a list may not exist! -- head ["a"] -> Just "a" -- head [1,2,3] -> Just 1 -- head [] -> Nothing head' : List a -> Maybe a head' [] = Nothing head' (x :: xs) = Just x {- the parameterized type Either aka. coproduct, sum, disjoint union Intuition: sticking two types together but remembering there are two halves, left and right -} data Either' : Type -> Type -> Type where Left' : a -> Either' a b Right' : b -> Either' a b headE : List a -> Either String a headE [] = Left "Head of empty list is nonsense" headE (x :: xs) = Right x -- Maybe a "=" Either a Unit -- example of a Type isomorphism maybe_to_either_u : Maybe a -> Either a Unit maybe_to_either_u Nothing = Right () maybe_to_either_u (Just x) = Left x either_u_to_maybe : Either a Unit -> Maybe a either_u_to_maybe (Left x) = Just x either_u_to_maybe (Right ()) = Nothing -- Check the above functions are mutual inverses: -- either_u_to_maybe (maybe_to_either_u x) = x -- maybe_to_either_u (either_u_to_maybe y) = y -- Later in the course we will see how to prove these equations