"The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise." ~ Edsger W. Dijkstra
Type: a set of values
data Vehicle = Car | Motorcycle
data Person = MkPerson Int Vehicle
Function: maps a set to another set
getVehicle :: Person -> Vehicle
getVehicle (MkPerson age vehicle) = vehicle
Fetch the head of a list
head :: [a] -> a
head (x:_) = x
head
is a partial functionCover the whole function domain
head :: [a] -> a
head (x:_) = x
head [] = error "empty list"
head []
calledChoose a better codomain
head :: [a] -> Maybe a
head (x:_) = Just x
head [] = Nothing
data Vehicle = Car | Motorcycle
data Person = MkPerson Int Vehicle
limit = 18
greet :: Person -> String
greet (MkPerson age _) | age < limit =
"Be patient, you're not old enough to drive!"
greet (MkPerson age Car) | age >= limit =
"Hello, you car driver!"
greet (MkPerson age Motorcycle) | age >= limit =
"Hello, you motorcycle driver!"
$ ghc -Wincomplete-patterns Greet.hs [1 of 1] Compiling Greet ( Greet.hs, Greet.o ) Greet.hs:7:1: warning: [-Wincomplete-patterns] Pattern match(es) are non-exhaustive In an equation for ‘greet’: Patterns not matched: (MkPerson _ Car) (MkPerson _ Motorcycle) | 7 | greet (MkPerson age _) | age < limit = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...
data Vehicle = Car | Motorcycle possiblyVehicle : Nat -> Type possiblyVehicle n = if n < 18 then () else Vehicle data Person : Type where MkPerson : (age : Nat) -> (v : possiblyVehicle age) -> Person greet : Person -> String greet (MkPerson age v) with (age < 18) greet (MkPerson _ ()) | True = "Be patient, you're not old enough to drive!" greet (MkPerson _ Car) | False = "Hello, you car driver!" greet (MkPerson _ Motorcycle) | False = "Hello, you motorcycle driver!"
The Idris compiler checks for exhaustiveness
λΠ> :total greet Greet.greet is Total
greet
function exhaustively covers all possible shapes and values of
type Person
Will this example program terminate? (taken from the paper Total Functional Programming)
loop :: Int -> Int
loop n = 1 + loop n
Mathematical reasoning in functional programming
loop :: Int -> Int
loop n = 1 + loop n
Substitute 0
for n
:
loop 0 = 1 + loop 0
Assume x - x = 0
and subtract loop 0
from both sides to get:
0 = 1
We went from the program
loop :: Int -> Int
loop n = 1 + loop n
to
0 = 1
n
is not only an integer, but also a bottom (undefined integer)loop
is a partial function, hence not suitable for equational
reasoningInexhaustive pattern matching and infinite loops
head :: [a] -> a
head (x:_) = x
loop :: Int -> Int
loop n = 1 + loop n
module RunFuel %default total data Fuel = Dry | More (Lazy Fuel) partial forever : Fuel forever = More forever data InfIO : Type where Do : IO a -> (a -> Inf InfIO) -> InfIO
infProg : InfIO infProg = Do (putStrLn "Lambda") (\_ => infProg) run : Fuel -> InfIO -> IO () run (More fuel) (Do c f) = do res <- c run fuel (f res) run Dry _ = putStrLn "Out of fuel" partial main : IO () main = run forever infProg
The run
function is total:
λΠ> :total run RunFuel.run is Total