Idris Tutorial

Stefan Wehr (wehr@cp-med.com)

28.2.2020

What are static types?

int addOne(int i) { return i+1; }

addOne(3);
addOne("3");  // Error, "3" is a string

What are dependent types?

boolOrChar : Bool -> Type
boolOrChar False = Char
boolOrChar True  = Bool

toString : (isChar : Bool) -> boolOrChar isChar -> String
toString False c    = singleton c  -- c is a Char 
toString True False = "F"          -- c is a Bool
toString True True  = "T"          -- c a Bool

What is Idris?

A first example in Idris: printf

data Format =
      FString Format     -- %s
    | FLit String Format -- a literal string
    | FEnd
-- "name = %s"
exampleFormat : Format
exampleFormat = FLit "name = " (FString FEnd)
toFormat : String -> Format
toFormat s = loop (unpack s)
  where
    prepend : Char -> Format -> Format
    prepend c (FLit s fmt) = FLit (strCons c s) fmt
    prepend c fmt          = FLit (singleton c) fmt
    loop : List Char -> Format
    loop []                   = FEnd
    loop ('%' :: 's' :: rest) = FString (loop rest)
    loop ('%' :: '%' :: rest) = prepend '%' (loop rest)
    loop (c :: rest)          = prepend c (loop rest)
PrintfType : Format -> Type
PrintfType (FString f) = String -> PrintfType f
PrintfType (FLit s f) = PrintfType f
PrintfType FEnd = String
printf' : (f : Format) -> String -> PrintfType f
printf' (FString x) acc = \s => printf' x (acc ++ s)
printf' (FLit x y) acc = printf' y (acc ++ x)
printf' FEnd acc = acc

printf : (s : String) -> PrintfType (toFormat s)
printf s = printf' (toFormat s) ""

Type-driven development

Vim Emacs Atom
Open response window \i
Reload file \r C-c C-l Cntl-Alt-R
Show type \t C-c C-t Cntl-Alt-T
Create definition \d C-c C-s Cntl-Alt-A
Case split \c C-c C-c Cntl-Alt-C
Proof search \p Cntl-Alt-S
%name Format f, f1, f2, f3

Exercise

Another example: length-indexed vectors

data Nat = Z | S Nat
infixr 7 ::

data Vect : Nat -> Type -> Type where
  Nil : Vect Z a
  (::) : a -> Vect n a -> Vect (S n) a

%name Vect xs,ys,zs,ws
total head : Vect (S n) a -> a
head (x :: _) = x

Exercises

total append : Vect n a -> Vect m a -> Vect (n + m) a
total zip : Vect n a -> Vect n b -> Vect n (a, b)
total elemAt : (k : Nat) -> Vect n a -> LT k n -> a

The predicates LT for < and LTE for <= are defined as follows:

-- Proofs that `n` is less than or equal to `m`
data LTE  : (n, m : Nat) -> Type where
  LTEZero : LTE Z n
  LTESucc : LTE left right -> LTE (S left) (S right)

-- Strict less than
total LT : Nat -> Nat -> Type
LT left right = LTE (S left) right

Idris and the real world

putStrLn :: String -> IO ()
getLine :: IO String

Example: sayHello

sayHello : IO ()
sayHello =
  do putStrLn "What's your name?"
     name <- getLine
     putStrLn ("Hello " ++ name)

Reading vectors from stdin

Dependent pair types

Exercise: implement readVect

readVect : IO (n : Nat ** Vect n String)
if condition
   then ...
   else ...

Exercise: read two vectors from stdin and zip them

Implement the function readAndZipVectors : IO (). The function should behave as follows:

Code generation

Resources

Things to take home