{-- -- TalTech ITI0212 -- -- Functional Programming -- -- week 8, 2022-03-16 -- -- Programming Interfaces --} module Lecture8 import Data.List {- Last time: monadic IO Today's lecture --------------- Interfaces (similar to typeclasses or abstract classes in other languages) These allow us to constrain generic functions, and provide a kind of 'ad-hoc polymorphism' or 'overloading' of functions. We will see some interfaces from the standard library, and define some of our own. In this lecture we focus on interfaces parameterized by basic types. In week 12 we will see more interfaces with 'higher-order' parameters. -} -- interface Num ty where -- (+) : ty -> ty -> ty -- (*) : ty -> ty -> ty -- fromInteger : Integer -> ty add : Num a => a -> a -> a add x y = x + y implementation Num Bool where (+) x y = (x && not y) || (not x && y) (*) x y = x && y fromInteger x = True {- Show: an interface for string representations of types -} interface Show' ty where show' : ty -> String implementation Show' Bool where show' False = "False" show' True = "True" -- Named implementations implementation [ind] Show Nat where show 0 = "Z" show (S k) = "S(" ++ show k ++ ")" -- show @{ind} 0 -- multiple constraints implementation [Lecture8] (Show a, Show b) => Show (Pair a b) where show (a, b) = "(" ++ show a ++ "," ++ show b ++ ")" {- Eq: an interface for equality/inequality -} -- interface Eq ty where -- (==) : ty -> ty -> Bool -- (/=) : ty -> ty -> Bool -- (/=) x y = not x == y -- for a function like occurences, we need to use the -- Eq constraint since the definition uses (==) occurrences : Eq a => (item : a) -> (l : List a) -> Nat occurrences item [] = 0 occurrences item (x :: xs) = case (x == item) of True => 1 + occurrences item xs False => occurrences item xs -- a type of arithmetic expressions data AExpr : Type -> Type where V : n -> AExpr n Plus : AExpr n -> AExpr n -> AExpr n Times : AExpr n -> AExpr n -> AExpr n eval : Num n => AExpr n -> n eval (V x) = x eval (Plus x y) = eval x + eval y eval (Times x y) = eval x * eval y -- let's say two arithmetic expressions are equal -- when they have the same denotation (evaluate to the same num) implementation (Num n, Eq n) => Eq (AExpr n) where t1 == t2 = eval t1 == eval t2 data Tree : Type -> Type where Leaf : Tree a Branch : (left : Tree a) -> (val : a) -> (right : Tree a) -> Tree a -- Equality for trees implementation Eq a => Eq (Tree a) where (==) Leaf Leaf = True (==) (Branch left val right) (Branch left' val' right') = left == left' && val == val' && right == right' (==) _ _ = False {- Ord : an interface for comparing values of orderable types -} -- interface Eq a => Ord a where -- compare : a -> a -> Ordering -- (<) : a -> a -> Bool -- (>) : a -> a -> Bool -- (<=) : a -> a -> Bool -- (>=) a -> a -> Bool -- max : a -> a -> a -- min : a -> a -> a -- sorting functions will typically need an Ord constraint -- if we want to use methods provided by Ord such as (<), (>=) quicksort : Ord a => List a -> List a quicksort [] = [] quicksort (x :: xs) = let lower = filter (< x) xs upper = filter (>= x) xs in (sort lower) ++ [x] ++ (sort upper) data Animal : Type where Insect : Animal Mouse : Animal Owl : Animal implementation Eq Animal where (==) Insect Insect = True (==) Mouse Mouse = True (==) Owl Owl = True (==) _ _ = False -- "Food Chain" implementation Ord Animal where Insect < Mouse = True Mouse < Owl = True Insect < Owl = True _ < _ = False {- Cast: an interface for casting types -} interface Cast' from to where cast' : from -> to implementation Num n => Cast (AExpr n) n where cast e = eval e -- see also: Integral, Neg, Fractional...