Lecture 8: Summary of Haskell course + Type Level Programming

Similar documents
Programming in Omega Part 1. Tim Sheard Portland State University

Lecture 4: Higher Order Functions

Type families and data kinds

COMP 3141 Software System Design and Implementation

IA014: Advanced Functional Programming

CSCI-GA Scripting Languages

CS457/557 Functional Languages

n n Try tutorial on front page to get started! n spring13/ n Stack Overflow!

GADTs. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 7. [Faculty of Science Information and Computing Sciences]

GADTs. Alejandro Serrano. AFP Summer School. [Faculty of Science Information and Computing Sciences]

Haskell Introduction Lists Other Structures Data Structures. Haskell Introduction. Mark Snyder

About the Tutorial. Audience. Prerequisites. Copyright & Disclaimer. Haskell Programming

Side Effects (3A) Young Won Lim 1/13/18

Advanced Type System Features Tom Schrijvers. Leuven Haskell User Group

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

GADTs. Wouter Swierstra. Advanced functional programming - Lecture 7. Faculty of Science Information and Computing Sciences

CPL 2016, week 10. Clojure functional core. Oleg Batrashev. April 11, Institute of Computer Science, Tartu, Estonia

Monad Background (3A) Young Won Lim 11/18/17

Advanced Topics in Programming Languages Lecture 2 - Introduction to Haskell

JVM ByteCode Interpreter

Background Type Classes (1B) Young Won Lim 6/28/18

Seminar on Languages for Scientific Computing Aachen, 6 Feb Navid Abbaszadeh.

GADTs. GADTs in Haskell

Monad Background (3A) Young Won Lim 11/8/17

Functional Programming. Overview. Topics. Definition n-th Fibonacci Number. Graph

Software System Design and Implementation

Programming with Universes, Generically

4. Functional Programming Language-Oriented Programming

Testing. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 2. [Faculty of Science Information and Computing Sciences]

Programming in Haskell Aug Nov 2015

CS 11 Haskell track: lecture 1

Logic - CM0845 Introduction to Haskell

Programming Languages 3. Definition and Proof by Induction

PROGRAMMING IN HASKELL. CS Chapter 6 - Recursive Functions

Lecture 2: List algorithms using recursion and list comprehensions

Introduction to Haskell

CSCE 314 Programming Languages

Shell CSCE 314 TAMU. Higher Order Functions

Functional Programming

CS558 Programming Languages

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Side Effects (3B) Young Won Lim 11/23/17

Side Effects (3B) Young Won Lim 11/20/17

Shared Subtypes. Subtyping Recursive Parameterized Algebraic Data Types

Side Effects (3B) Young Won Lim 11/27/17

Haske k ll An introduction to Functional functional programming using Haskell Purely Lazy Example: QuickSort in Java Example: QuickSort in Haskell

Shell CSCE 314 TAMU. Haskell Functions

Programming Languages and Techniques (CIS120)

Declarative concurrency. March 3, 2014

An introduction introduction to functional functional programming programming using usin Haskell

Depending on Types. Stephanie Weirich University of Pennsylvania

Haskell 101. (Version 1 (July 18, 2012)) Juan Pedro Villa Isaza

Haskell: From Basic to Advanced. Part 2 Type Classes, Laziness, IO, Modules

Course year Typeclasses and their instances

CS 360: Programming Languages Lecture 10: Introduction to Haskell

CS 360: Programming Languages Lecture 12: More Haskell

Advanced features of Functional Programming (Haskell)

Practical Haskell. An introduction to functional programming. July 21, Practical Haskell. Juan Pedro Villa-Isaza. Introduction.

Functional Logic Programming Language Curry

Haskell 98 in short! CPSC 449 Principles of Programming Languages

Exercise 1 ( = 24 points)

CS 320: Concepts of Programming Languages

LECTURE 16. Functional Programming

Universes. Universes for Data. Peter Morris. University of Nottingham. November 12, 2009

Type checking by theorem proving in IDRIS

CSCE 314 TAMU Fall CSCE 314: Programming Languages Dr. Flemming Andersen. Haskell Basics

Programming Systems in Artificial Intelligence Functional Programming

CSC312 Principles of Programming Languages : Functional Programming Language. Copyright 2006 The McGraw-Hill Companies, Inc.

CS558 Programming Languages

Lists. Michael P. Fourman. February 2, 2010

Advances in Programming Languages

Haskell Overloading (1) LiU-FP2016: Lecture 8 Type Classes. Haskell Overloading (3) Haskell Overloading (2)

CS 457/557: Functional Languages

Haskell: Lists. CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Friday, February 24, Glenn G.

Overview. Elements of Programming Languages. Evaluation order. Evaluation order

Adam Chlipala University of California, Berkeley ICFP 2006

Lecture 5: Lazy Evaluation and Infinite Data Structures

CS 440: Programming Languages and Translators, Spring 2019 Mon

An introduction to functional programming. July 23, 2010

CSC324 Principles of Programming Languages

SCHEME 10 COMPUTER SCIENCE 61A. July 26, Warm Up: Conditional Expressions. 1. What does Scheme print? scm> (if (or #t (/ 1 0)) 1 (/ 1 0))

MoreIntro_annotated.v. MoreIntro_annotated.v. Printed by Zach Tatlock. Oct 04, 16 21:55 Page 1/10

CSCE 314 TAMU Fall CSCE 314: Programming Languages Dr. Flemming Andersen. Haskell Functions

CIS 194: Homework 6. Due Monday, February 25. Fibonacci numbers

A Second Look At ML. Chapter Seven Modern Programming Languages, 2nd ed. 1

CIS 194: Homework 6. Due Wednesday, 4 March. Fibonacci numbers. It s all about being lazy.

Functional Programming Lecture 13: FP in the Real World

Functional Programming in Haskell for A level teachers

Tapir: a language for verified OS kernel probes

Functional Programming

According to Larry Wall (designer of PERL): a language by geniuses! for geniuses. Lecture 7: Haskell. Haskell 98. Haskell (cont) - Type-safe!

Functional Programming in Haskell Part I : Basics

Haskell An Introduction

Theorem Proving Principles, Techniques, Applications Recursion

Background Operators (1E) Young Won Lim 7/7/18

Dependent Polymorphism. Makoto Hamana

Object-Oriented Design Lecture 23 CS 3500 Fall 2009 (Pucella) Tuesday, Dec 8, 2009

Programming Paradigms

Provably Correct Software

Programming with Math and Logic

Transcription:

Lecture 8: Summary of Haskell course + Type Level Programming Søren Haagerup Department of Mathematics and Computer Science University of Southern Denmark, Odense October 31, 2017

Principles from Haskell can be reused in other languages Sample piece of Java code If we should use some principles learned from this course, how would we change this source code?

Principles from Haskell can be reused in other languages Write programs using small, pure functions, which are easy to test and reason about Transform data using higher-order functions map, filter and foldl/foldr/reduce Minimize mutation Minimize implicit dependencies Isolate side-effects Avoid doing IO everywhere in your program

Types and Immutability Mutable Immutable data structures data structures Dynamically typed Python Clojure (JVM) PHP Elixir (Erlang VM) Statically typed Java (JVM), C# (CLR) Haskell C Scala (JVM) There is a current trend towards more types and more precise types in programming languages.

Nullable types In C# we see something like the Maybe type constructor the nullable types: 4

TypeScript Taking a dynamically typed language (JavaScript) and turning it into a statically typed language. Compiler flags and LINT rules can be used to control how many types are required from the programmer. TypeScript is a superset of Javascript, and with the most relaxed compiler flags, normal JavaScript can compile using the TypeScript compiler. 5

Introduction Type level programming is an activity which can only be performed in languages with advanced type system features. 6

Introduction Type level programming is an activity which can only be performed in languages with advanced type system features. Scala and Haskell are general-purpose languages where it is possible to do some Type-level programming. 6

Introduction Type level programming is an activity which can only be performed in languages with advanced type system features. Scala and Haskell are general-purpose languages where it is possible to do some Type-level programming. It might seem strange at first, but it is actually useful - we will also see examples of this. 6

Peano numbers represented by types Recall the peano numbers data Nat = Z S Nat where the numbers 0,1,2... are represented by the values Z, S Z, S (S Z).... 7

Peano numbers represented by types Recall the peano numbers data Nat = Z S Nat where the numbers 0,1,2... are represented by the values Z, S Z, S (S Z).... If we were to define this on the type level instead, we could introduce empty data declarations. data Z data S n where the numbers 0,1,2... are represented by the types Z, S Z, S (S Z).... The only member of the types is. I.e. :: S (S Z). 7

Type Classes Prolog Predicates So let s say that we have defined data Z data S n It turns out that the Prolog program even(z). even(s(n)):-odd(n). odd(s(n)):-even(n). corresponds quite closely to the following Haskell construction: class Even n class Odd n instance Even Z instance Odd n Even (S n) instance Even n Odd (S n) 8

Prolog/Haskell sessions?- even(z). yes?- even(s(z)). no In the Haskell context, the type n is even, if it is an instance of the type class Even n. > :t ( :: ((Even n) n)) :: Z ( :: ((Even n) n)) :: Z :: Z > :t ( :: ((Even n) n)) :: S Z < interactive >: 1 : 2 : No instance for (Odd Z) arising from an expression type signature In the expression : ( :: Even n n) :: S Z 9

Defining addition for our type level numbers add(0,b,b). add(s(a),b,s(c)) :- add(a,b,c). We can model this relation using multiparameter type classes class Add a b c instance Add Z b b instance Add a b c Add (S a) b (S c) 10

Defining addition for our type level numbers class Add a b c instance Add Z b b instance Add a b c Add (S a) b (S c) We can now verify an addition 1+3 = 4. To help us, define the following values : one :: S Z one = three :: S (S (S Z)) three = add :: Add a b c a b c add = The addition is verified, since the following query type checks: > :t add one three :: S (S (S (S Z))) add one three :: S (S (S (S Z))) :: S (S (S (S Z))) 11

Multiparameter type classes + Functional dependencies Type level Functions To define type level functions and not just relations, we need a way to tell the compiler, that the result can be computed from the input. In Haskell, one can write: class Add a b c a b c instance Add Z b b instance Add a b c Add (S a) b (S c) > :t add three three add three three :: S (S (S (S (S (S Z))))) 12

Practical Example: Length-indexed lists We would like to introduce a data type Vec a n which represents lists containing elements of type a, which is of length n. For example: [ ] :: Vec Char Z [ a ] :: Vec a (S Z) [ a, b ] :: Vec a (S (S Z)) [ a, b, c ] :: Vec a (S (S (S Z))) 13

Practical Example: Length-indexed lists We would like to introduce a data type Vec a n which represents lists containing elements of type a, which is of length n. For example: [ ] :: Vec Char Z [ a ] :: Vec a (S Z) [ a, b ] :: Vec a (S (S Z)) [ a, b, c ] :: Vec a (S (S (S Z))) We could then define head :: Vec a (S n) a tail :: Vec a (S n) Vec a n safezip :: Vec a n Vec b n Vec (a, b) n 13

Practical Example: Length-indexed lists We would like to introduce a data type Vec a n which represents lists containing elements of type a, which is of length n. For example: [ ] :: Vec Char Z [ a ] :: Vec a (S Z) [ a, b ] :: Vec a (S (S Z)) [ a, b, c ] :: Vec a (S (S (S Z))) We could then define head :: Vec a (S n) a tail :: Vec a (S n) Vec a n safezip :: Vec a n Vec b n Vec (a, b) n Notice that head and tail would then be total functions, since the type checker discards the empty list. 13

Why is it useful? 1. At compile time, we can make sure that the program will never fail due to list length errors. 14

Why is it useful? 1. At compile time, we can make sure that the program will never fail due to list length errors. 2. When implementing a matrix multiplication algorithm, where a matrix of size m n should be multiplied by a matrix of size n k, we do not need error handling in our code, if we are just working with types like the one presented here. 14

Why is it useful? 1. At compile time, we can make sure that the program will never fail due to list length errors. 2. When implementing a matrix multiplication algorithm, where a matrix of size m n should be multiplied by a matrix of size n k, we do not need error handling in our code, if we are just working with types like the one presented here. 3. There is no runtime overhead incurred by the extra type-level information - it is only used at compile time. 14

Introducing Generalized Algebraic Data Types (GADTs) It is not obvious how to define a type Vec with the properties from the previous slide, from what we have learned in this course. The modern way to achieve it in Haskell is to use a Generalized Algebraic Data Type (GADTs). 15

Introducing Generalized Algebraic Data Types (GADTs) The traditional ADT for lists data List a = Nil Cons a (List a) can be written in GADT-notation by data List a where Nil :: List a Cons :: a List a List a We specify the complete type signature of the data constructors. Referring to our types Z and S n from earlier, we can define data Vec :: where Nil :: Vec a Z Cons :: a Vec a n Vec a (S n) 16

head, tail and safezip Now we can define the functions announced earlier: head :: Vec a (S n) a head (Cons x ) = x tail :: Vec a (S n) Vec a n tail (Cons xs) = xs safezip :: Vec a n Vec b n Vec (a, b) n safezip Nil Nil = Nil safezip (Cons x xs) (Cons y ys) = Cons (x, y) (safezip xs ys) 17

Implementing replicate We would like to implement replicate for our length-indexed vectors. replicate :: n a Vec n a What is wrong with this type? 18

Implementing replicate We would like to implement replicate for our length-indexed vectors. replicate :: n a Vec n a What is wrong with this type? The previously mentioned functions only used S n and Z on the type level. But sometimes it is useful to give S n and Z as arguments to functions. 18

Singleton types: Chaining the type and the value level together But we can add a singleton-type Nat which connects the value level and the type level: data Nat nat where Z :: Nat Z S :: Nat n Nat (S n) Then we can define replicate :: Nat n a Vec n a replicate Z = Nil replicate (S n) x = Cons x (replicate n x) 19

What would be the type of ( +)? Let s say we give input lists xs :: Vec a n and ys :: Vec a m. What could be a proper type for ( +) ::? Nil + ys = ys (Cons x xs) + ys = Cons x (xs + ys) 20

What would be the type of ( +)? Let s say we give input lists xs :: Vec a n and ys :: Vec a m. We can use our type class from earlier: ( +) :: (Add n m r) Vec a n Vec a m Vec a r Nil + ys = ys (Cons x xs) + ys = Cons x (xs + ys) 21

What would be the type of ( +)? Let s say we give input lists xs :: Vec a n and ys :: Vec a m. We can use our type class from earlier: ( +) :: (Add n m r) Vec a n Vec a m Vec a r Nil + ys = ys (Cons x xs) + ys = Cons x (xs + ys) We can end up with a function ( +) with the type given above, but we need to write the definition a bit differently. 21

Defining ( +) as a part of the Add type class class Add a b c a b c where ( +) :: Vec t a Vec t b Vec t c instance Add Z b b where Nil + ys = ys instance Add a b c Add (S a) b (S c) where (Cons x xs) + ys = Cons x (xs + ys) 22

Making life easier again Haskell Programmers have not been so happy about the solution from before: ( +) :: (Add n m r) Vec a n Vec a m Vec a r They asked: 1. Why do we need to add a type class constraint? 23

Making life easier again Haskell Programmers have not been so happy about the solution from before: ( +) :: (Add n m r) Vec a n Vec a m Vec a r They asked: 1. Why do we need to add a type class constraint? 2. Why do we have to do our type level programming using the logical programming paradigm? 23

Making life easier again Haskell Programmers have not been so happy about the solution from before: ( +) :: (Add n m r) Vec a n Vec a m Vec a r They asked: 1. Why do we need to add a type class constraint? 2. Why do we have to do our type level programming using the logical programming paradigm? Wouldn t it be better to introduce a way to write type level functions using functional programming paradigm, and end up with a type like ( +) :: Vec a n Vec a m Vec a (n :+ m) where (:+ ) is a function on types? 23

Type families Type level functions The following is a quite new feature of Haskell: infixl 6 :+ type family n1 :+ n2 :: type instance Z :+ n2 = n2 type instance S n1 :+ n2 = S (n1 :+ n2) infixr 5 + ( +) :: Vec a n1 Vec a n2 Vec a (n1 :+ n2) Nil + ys = ys Cons x xs + ys = Cons x (xs + ys) 24

Practical example: Function with variable number of arguments Say, we would like to implement the following family of functions that sum up their integer arguments: sum n :: Int 1 Int n Int sum n = λi 1 λi n i 1 + + i n 25

Solution using a Type Family type family MultiArgs n a :: type instance MultiArgs Z a = a type instance MultiArgs (S n) a = a MultiArgs n a 26

Solution using a Type Family type family MultiArgs n a :: type instance MultiArgs Z a = a type instance MultiArgs (S n) a = a MultiArgs n a sum :: Nat n Int MultiArgs n Int sum Z acc = acc sum (S n) acc = λi sum n (acc + i) sum :: Nat n MultiArgs n Int sum n = sum n 0 26

Example GHCi session: > sum Z 0 > sum (S Z) Solution using a Type Family < interactive >: 3 : 1 : No instance for (Show (Int Int)) arising from a use of print In a stmt of an interactive GHCi command : print it > sum (S Z) 3 3 > sum (S (S Z)) 3 4 7 27

Dependently Typed Programming A dependent type is a type that depends on a value. 28

Dependently Typed Programming A dependent type is a type that depends on a value. A dependent function s return type may depend on the value of an argument 28

Dependently Typed Programming A dependent type is a type that depends on a value. A dependent function s return type may depend on the value of an argument The examples we have just seen with length-indexed vectors and functions with a variable number of arguments, are examples of dependently typed programming. 28

Phase distinction: Types are not values In Haskell, types and values live in different scopes. We can use singleton types to chain types and values together. 29

Phase distinction: Types are not values In Haskell, types and values live in different scopes. We can use singleton types to chain types and values together. Very recent versions of GHC have automatical promotion of value level constructions to the type level. 29

Phase distinction: Types are not values In Haskell, types and values live in different scopes. We can use singleton types to chain types and values together. Very recent versions of GHC have automatical promotion of value level constructions to the type level. In general, features from the value level are being ported to the type level (functions type families), 29

Phase distinction: Types are not values In Haskell, types and values live in different scopes. We can use singleton types to chain types and values together. Very recent versions of GHC have automatical promotion of value level constructions to the type level. In general, features from the value level are being ported to the type level (functions type families), In general, features from the type level are being ported to the kind level (type polymorphism kind polymorphism) 29

Phase distinction: Types are not values In Haskell, types and values live in different scopes. We can use singleton types to chain types and values together. Very recent versions of GHC have automatical promotion of value level constructions to the type level. In general, features from the value level are being ported to the type level (functions type families), In general, features from the type level are being ported to the kind level (type polymorphism kind polymorphism) Other languages, like Agda and Coq have an infinite stack of levels. And concepts from lower levels can be used on higher leves. In Haskell, for now, we are restricted to the small hierarchy value : type : kind : sort which - for practical purposes - seems to be enough. 29

A taste of the Curry-Howard Isomorphism using Haskell A deep result from Computer Science, is the direct relationship between computer programs and mathematical proofs. This correspondance is the foundation of programming languages like Agda and Coq Essentially there is a bijection such that Mathematical Propositions Types Mathematical Proofs Programs 30

A taste of the Curry-Howard Isomorphism using Haskell The reverse function is essentially the following: reverse :: Vec a n Vec a n reverse xs = go Nil xs go :: Vec a m Vec a k Vec a (k :+ m) go acc Nil = acc go acc (Cons x xs) = go (Cons x acc) xs 31

A taste of the Curry-Howard Isomorphism using Haskell The reverse function is essentially the following: reverse :: Vec a n Vec a n reverse xs = go Nil xs go :: Vec a m Vec a k Vec a (k :+ m) go acc Nil = acc go acc (Cons x xs) = go (Cons x acc) xs But it does not type check out of the box... It comes up with two quite clear error messages, though: 1. In def. of reverse: Couldn t match type n with n :+ Z 2. In def. of go: Could not deduce ((n :+ S m) S (n :+ m)) from the context (k S n) bound by a pattern with constructor Cons :: a Vec a n Vec a (S n) 31

A taste of the Curry-Howard Isomorphism using Haskell We essentially need to prove the following statements about our Peano numbers defined on type level and n.n :+ Z n n, m.(n :+ (S m)) (S (n :+ m)) As indicated earlier, a proof corresponds to program code. 32

A taste of the C-H Iso. using Haskell Below, we have extended our reverse definition with the needed proofs: go :: Vec a m Vec a k Vec a (k :+ m) go acc Nil = acc go acc (Cons x xs) = subst (plus suc (size xs) (size acc)) $ go (Cons x acc) xs reverse :: Vec a n Vec a n reverse xs = subst (plus zero (size xs)) $ go Nil xs I have not explained how subst, size, plus suc and plus size is defined 1 - this could be a subject for another course. 1 The details can be found on http://dev.stephendiehl.com/hask/#advanced-proofs 33

This is it This was the last lecture of the Haskell part of the Programming Languages course. 34

This is it This was the last lecture of the Haskell part of the Programming Languages course. The obligatory assignment, due 13th of November at 23.59 is the first half of your exam. 34

This is it This was the last lecture of the Haskell part of the Programming Languages course. The obligatory assignment, due 13th of November at 23.59 is the first half of your exam. My exam is The course evaluation, to be filled out by you now. To remind you, this was what we covered in each of the 8 lectures: 1. Expressions, Types and Patterns 2. List algorithms, explicit recursion and list comprehensions 3. List algorithms using higher order functions 4. Algebraic Data Types 5. Lazy Evaluation and Infinite Data Structures 6. Proving and Testing Program Properties 7. Monads and IO 8. Type Level Programming 34