[ Faculty of Science Information and Computing Sciences] 1 Concepts of programming languages Idris Žan Palčič, Stefan Koppier, Kevin Namink, Luca Scannapieco and Xander van der Goot
[ Faculty of Science Information and Computing Sciences] 2 Introduction Idris is a general purpose pure functional programming language with dependent types. This language supports features that allow it to prove properties of functions. Development of Idris is led by Edwin Brady. Its first stable release was in April 2017.
[ Faculty of Science Information and Computing Sciences] 3 Table of contents ▶ Basics ▶ Dependent types ▶ Type driven programming ▶ Using types to express properties of data ▶ Expressing contracts in types ▶ Conclusions ▶ Questions
[ Faculty of Science Basics 4 Basics Table of contents Information and Computing Sciences] ▶ Basics ▶ Dependent types ▶ Type driven programming ▶ Using types to express properties of data ▶ Expressing contracts in types ▶ Conclusions ▶ Questions ▶ Pure functional ▶ Strict ▶ Syntax, similar to Haskell ▶ Total functions ▶ Dependent types
▶ Functions don’t have side effects such as modifying global ▶ As a result, for any specific inputs, a function will always give the [ Faculty of Science Information and Computing Sciences] 5 Pure functional Following the definition from “Type driven development with Idris” in a functional programming language: And in a pure functional language: variables, throwing exceptions, or preforming console input or output. same result. ▶ Programs are composed of functions ▶ Program execution consists of evaluation of functions ▶ Functions are a first-class language construct
[ Faculty of Science Information and Computing Sciences] 5 Pure functional Following the definition from “Type driven development with Idris” in a functional programming language: And in a pure functional language: variables, throwing exceptions, or preforming console input or output. same result. ▶ Programs are composed of functions ▶ Program execution consists of evaluation of functions ▶ Functions are a first-class language construct ▶ Functions don’t have side effects such as modifying global ▶ As a result, for any specific inputs, a function will always give the
[ Faculty of Science Information and Computing Sciences] 6 Strict Idris uses strict evaluation by default but has a Lazy keyword. As example the ifThenElse function in the basic library: ifThenElse : Bool -> (t: Lazy a) -> (e: Lazy a) -> a t e = t ifThenElse True ifThenElse False t e = e
[ Faculty of Science Information and Computing Sciences] 7 Types Types are first class citizens. StringOrInt : Bool -> Type StringOrInt False -> String StringOrInt True -> Int
[ Faculty of Science Information and Computing Sciences] 8 Similarity to other languages Idris is able to write tactic invocations to prove invariants at compile time, similar to Coq . It is also possible to interactively elaborate with a proof term, similar to Epigram and Agda The syntax of Idris is very similar to Haskell .
[ Faculty of Science Information and Computing Sciences] 9 Syntax differences with Haskell Idris: foo : Nat -> Nat Haskell: foo :: Nat -> Nat ▶ Colon ▶ Type signature mandatory ▶ Omission of “where” in module declarations ▶ Dependent types
▶ The append function for finite lists is total. ▶ The first function for a list is partial, it is not defined if the list is [ Faculty of Science Information and Computing Sciences] 10 Total functions A way to prove properties of functions. Idris can distinct between functions that are total and that are partial . Total functions are guaranteed to return a value in finite time for every well-typed input. infinite loop. Examples are: empty. ▶ Total functions return a value in finite time. ▶ Partial functions return a value if it doesn’t crash or enter an
[ Faculty of Science Information and Computing Sciences] 10 Total functions A way to prove properties of functions. Idris can distinct between functions that are total and that are partial . Total functions are guaranteed to return a value in finite time for every well-typed input. infinite loop. Examples are: empty. ▶ Total functions return a value in finite time. ▶ Partial functions return a value if it doesn’t crash or enter an ▶ The append function for finite lists is total. ▶ The first function for a list is partial, it is not defined if the list is
[ Faculty of Science Information and Computing Sciences] 11 Dependent types Table of contents ▶ Basics ▶ Dependent types ▶ Type driven programming ▶ Using types to express properties of data ▶ Expressing contracts in types ▶ Conclusions ▶ Questions
[ Faculty of Science Information and Computing Sciences] 12 Dependent types Idris has dependent types, this means types can depend on other values. The most clear example is the Vect type that is used for lists.
[ Faculty of Science Information and Computing Sciences] 13 Dependent types For example, appending a list of length 3 of strings with a list of length 4 of strings: and Vect 4 String . And return a type Vect 7 String . ▶ Simple programming languages would use a type AnyList . ▶ Generic programming languages would instead use List String . ▶ But using dependent types would use the types: Vect 3 String
[ Faculty of Science Information and Computing Sciences] Type driven programming Interactive editing Table of contents Type driven programming 14 ▶ Basics ▶ Dependent types ▶ Type driven programming ▶ Using types to express properties of data ▶ Expressing contracts in types ▶ Conclusions ▶ Questions ▶ Type ▶ Define ▶ Refine
[ Faculty of Science Information and Computing Sciences] 15 Interactive editing Type Defining vectors: data Vect : Nat -> Type -> Type where Nil : Vect Z a (::) : (x : a) -> (xs : Vect k a) -> Vect (S k) a
[ Faculty of Science Information and Computing Sciences] 16 Interactive editing Define Append function with vect data type: ys = ?append1 app (x :: xs) ys = ?append2 app : Vect n a -> Vect m a -> Vect (n + m) a app Nil
app : Vect n a -> Vect m a -> Vect (n + m) a app Nil [ Faculty of Science can check the type of ?append2 and ?append1 to find: ys = ys or search on each of the holes resulting in this: append2 : Vect (S (plus len m)) a append1 : Vect m a Holes are useful because they help us write functions incrementally. We Information and Computing Sciences] app (x :: xs) ys = ?append2 ys = ?append1 app : Vect n a -> Vect m a -> Vect (n + m) a Refine Interactive editing 17 app (x :: xs) ys = x :: app xs ys app Nil
[ Faculty of Science Information and Computing Sciences] ys = ys or search on each of the holes resulting in this: append2 : Vect (S (plus len m)) a append1 : Vect m a can check the type of ?append2 and ?append1 to find: Holes are useful because they help us write functions incrementally. We app (x :: xs) ys = ?append2 ys = ?append1 app : Vect n a -> Vect m a -> Vect (n + m) a Refine Interactive editing 17 app (x :: xs) ys = x :: app xs ys app Nil app : Vect n a -> Vect m a -> Vect (n + m) a app Nil
[ Faculty of Science Information and Computing Sciences] 18 What if we can’t make guarantees at compile time? ▶ Dependent pairs
[ Faculty of Science Information and Computing Sciences] 19 What if we can’t make guarantees at compile time? What we’ve seen works for types which we know at compile time. But what if the size of the vectors are not known at compile time? For example, when we want the user to enter elements on the console until the empty string is entered. do x <- getLine if x == "" then return [] else do xs <- readVect return (x :: xs) But this won’t type check. readVect : IO (Vect n String) readVect =
[ Faculty of Science then return (MkVect 0 []) But this approach results in a lot of boilerplate code if we need to do vector type check correctly. we don’t need to know the size of the vector, which we can use to let the Now we can construct a VectUnknown which contains the size. As such, return (MkVect (1 + n) (x :: xs)) else do MkVect n xs <- readVect if x == "" Information and Computing Sciences] do x <- getLine readVect : IO (VectUnknown String) MkVect : (n : Nat) -> Vect n a -> VectUnknown a data VectUnknown : Type -> Type where Encapsulate Vect in a different type 20 this for a lot of different types. readVect =
[ Faculty of Science then return (MkVect 0 []) But this approach results in a lot of boilerplate code if we need to do vector type check correctly. we don’t need to know the size of the vector, which we can use to let the Now we can construct a VectUnknown which contains the size. As such, return (MkVect (1 + n) (x :: xs)) else do MkVect n xs <- readVect if x == "" Information and Computing Sciences] do x <- getLine readVect : IO (VectUnknown String) MkVect : (n : Nat) -> Vect n a -> VectUnknown a data VectUnknown : Type -> Type where Encapsulate Vect in a different type 20 this for a lot of different types. readVect =
Recommend
More recommend