Lazy Functional Programming in Haskell

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

Standard prelude. Appendix A. A.1 Classes

Functional Programming Mid-term exam Tuesday 3/10/2017

INTRODUCTION TO HASKELL

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

(ii) Define a function ulh that takes a list xs, and pairs each element with all other elements in xs.

Lecture 4: Higher Order Functions

Haskell Types, Classes, and Functions, Currying, and Polymorphism

Introduction to Haskell

Part 0. A (Not So) Brief Introduction to Haskell

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

Higher Order Functions in Haskell

A general introduction to Functional Programming using Haskell

301AA - Advanced Programming

Haskell Overview II (2A) Young Won Lim 8/9/16

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

CS 457/557: Functional Languages

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

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

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

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

Principles of Programming Languages (H)

CSCE 314 Programming Languages

Haskell & functional programming, some slightly more advanced stuff. Matteo Pradella

Shell CSCE 314 TAMU. Higher Order Functions

Haskell An Introduction

Imperative languages

Programming Languages Fall 2013

Functional Programming and Haskell

An introduction to functional programming. July 23, 2010

Functional Programming for Logicians - Lecture 1

Haskell: From Basic to Advanced. Part 3 A Deeper Look into Laziness

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

EDAF40. 2nd June :00-19:00. WRITE ONLY ON ONE SIDE OF THE PAPER - the exams will be scanned in and only the front/ odd pages will be read.

Lecture 5: Lazy Evaluation and Infinite Data Structures

Overloading, Type Classes, and Algebraic Datatypes

Advanced Programming Handout 7. Monads and Friends (SOE Chapter 18)

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

An introduction introduction to functional functional programming programming using usin Haskell

Logic - CM0845 Introduction to Haskell

Advanced features of Functional Programming (Haskell)

An Introduction to Programming in Haskell. Gabriel J. Ferrer Hendrix College

Programming Paradigms

JVM ByteCode Interpreter

Programming in Haskell Aug Nov 2015

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

CSCE 314 Programming Languages

Functional Programming

CS 340 Spring 2019 Midterm Exam

Principles of Programming Languages

Principles of Programming Languages, 3

CS 320: Concepts of Programming Languages

Introduction to Functional Programming in Haskell 1 / 56

INDEX. Symbols & Numbers. Learn You a Haskell for Great Good! 2011 by Miran Lipovača

CSC324 Principles of Programming Languages

Optimising Functional Programming Languages. Max Bolingbroke, Cambridge University CPRG Lectures 2010

Haskell: From Basic to Advanced. Haskell buzzwords. Hello, World! History. Haskell 98 / Haskell 2010 GHC

Haskell Overview II (2A) Young Won Lim 8/23/16

CS 320 Midterm Exam. Fall 2018

Introduction to Functional Programming and Haskell. Aden Seaman

Informatics 1 Functional Programming Lecture 12. Data Abstraction. Don Sannella University of Edinburgh

CMSC 330: Organization of Programming Languages. Functional Programming with Lists

Haskell Types COMP360

Lecture 2: List algorithms using recursion and list comprehensions

Informatics 1 Functional Programming Lecture 11. Data Representation. Don Sannella University of Edinburgh

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

Little and not so big bits of Haskell

CS 440: Programming Languages and Translators, Spring 2019 Mon

PROGRAMMING IN HASKELL. CS Chapter 6 - Recursive Functions

Introduction to Haskell

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

Exercises on ML. Programming Languages. Chanseok Oh

Programming with Math and Logic

HIGHER-ORDER FUNCTIONS

CMSC 330: Organization of Programming Languages. Functional Programming with Lists

CS 360: Programming Languages Lecture 10: Introduction to Haskell

Introduction. Wouter Swierstra. Applied functional programming. Faculty of Science Information and Computing Sciences

Course year Typeclasses and their instances

Informatics 1 Functional Programming Lecture 7. Map, filter, fold. Don Sannella University of Edinburgh

Topic 6: Partial Application, Function Composition and Type Classes

Topic 6: Partial Application, Function Composition and Type Classes

Haskell Overview II (2A) Young Won Lim 9/26/16

Monads seen so far: IO vs Gen

Monads in Haskell. Nathanael Schilling. December 12, 2014

A tour of the Haskell Prelude

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))

Type-indexed functions in Generic Haskell

Lecture 10 September 11, 2017

Haskell Revision and Exercises

301AA - Advanced Programming [AP-2017]

CSE 130 [Winter 2014] Programming Languages

CIS 120 Midterm I February 16, 2015 SOLUTIONS

f() ! " Run a higher-priority task? ! " Yield the processor to another task because our ! " Use the processor for some other activity while

CS 410/510: Advanced Programming

Functional Programming TDA 452, DIT 142

Solution sheet 1. Introduction. Exercise 1 - Types of values. Exercise 2 - Constructors

Documentation for the Idris Language. Version 0.99

Box-and-arrow Diagrams

Programming Systems in Artificial Intelligence Functional Programming

CS 11 Haskell track: lecture 1

Transcription:

Lazy Functional Programming in Haskell David Raymond Christiansen 25 November, 2013

What is Haskell? 2

What is Haskell? Pure functional language: no side effects 2

What is Haskell? Pure functional language: no side effects Lazy evaluation: function arguments are evaluated when needed 2

What is Haskell? Pure functional language: no side effects Lazy evaluation: function arguments are evaluated when needed Rich type system: higher-order types 2

Just the latest hipster fad?

Why Should I Care? Get better at functional programming 4

Why Should I Care? Get better at functional programming Laboratory for new language features use the future, today! 4

Why Should I Care? Get better at functional programming Laboratory for new language features use the future, today! Very mature compiler and tools 4

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 5

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 6

Hello, world module Main main :: IO () main = do putstrln "Who are you?" name <- getline putstrln ("Hello, " ++ name) 6

Fibonacci fib :: Int -> Int fib 0 = 0 fib 1 = 1 fib n = fib (n - 1) + fib (n - 2) 7

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 8

Expressions Function application: f x y z 8

Expressions Function application: f x y z Anonymous functions: \x y -> x + y 8

Expressions Function application: f x y z Anonymous functions: \x y -> x + y Infix operators: f x + 3 8

Expressions Function application: f x y z Anonymous functions: \x y -> x + y Infix operators: f x + 3 Infix function application: 2 elem [1, 2, 3] 8

Expressions Function application: f x y z Anonymous functions: \x y -> x + y Infix operators: f x + 3 Infix function application: 2 elem [1, 2, 3] Prefix operator application: (+) 1 2 8

Expressions Function application: f x y z Anonymous functions: \x y -> x + y Infix operators: f x + 3 Infix function application: 2 elem [1, 2, 3] Prefix operator application: (+) 1 2 Operator slices: map (+ 1) [1, 2, 3] 8

Expressions Function application: f x y z Anonymous functions: \x y -> x + y Infix operators: f x + 3 Infix function application: 2 elem [1, 2, 3] Prefix operator application: (+) 1 2 Operator slices: map (+ 1) [1, 2, 3] Function composition: f. g = \x -> f (g x) 8

Function Definitions F#: let rec reverse (lst : a list) : a list = match lst with [] => [] (x::xs) => reverse xs @ [x] 9

Function Definitions F#: let rec reverse (lst : a list) : a list = match lst with [] => [] (x::xs) => reverse xs @ [x] Haskell: reverse :: [a] -> [a] reverse [] = [] reverse (x:xs) = reverse xs ++ [x] 9

Where blocks reverse :: [a] -> [a] reverse xs = helper [] xs where helper acc [] = acc helper acc (y:ys) = helper (y:acc) ys Put the interesting part first! 10

Data Definitions data Maybe a = Just a Nothing 11

Data Definitions data Maybe a = Just a Nothing data List a = Cons a (List a) Nil 11

Data Definitions data Maybe a = Just a Nothing data List a = Cons a (List a) Nil data Tree a = Empty Node (Tree a) a (Tree a) 11

Data Definitions data Maybe a = Just a Nothing data List a = Cons a (List a) Nil data Tree a = Empty Node (Tree a) a (Tree a) data Either a b = Left a Right b 11

Data Definitions data Maybe a = Just a Nothing data List a = Cons a (List a) Nil data Tree a = Empty Node (Tree a) a (Tree a) data Either a b = Left a Right b data Labeled a = Labeled String a 11

Case Sensitivity UPPERCASE Types Constructors Type constructors Modules 12

Case Sensitivity UPPERCASE Types Constructors Type constructors Modules LOWERCASE Variables Type variables Defined operators 12

Indentation Haskell is indentation-sensitive (like F#): reverse :: [a] -> [a] reverse xs = helper [] xs where helper acc [] = acc helper acc (y:ys) = helper (y:acc) ys won t compile. 13

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 14

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 14

Lazy Evaluation STRICT EVALUATION evaluates arguments before calling functions LAZY EVALUATION evaluates arguments as they are used 14

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) [3,4,5])) 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) [3,4,5])) ==> (map show [4,5,6]) 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) [3,4,5])) ==> (map show [4,5,6]) ==> ["4","5","6"] 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) [3,4,5])) ==> (map show [4,5,6]) ==> ["4","5","6"] Lazy: (map show. map (+1). filter (>2)) [1,2,3,4,5] 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) [3,4,5])) ==> (map show [4,5,6]) ==> ["4","5","6"] Lazy: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) [3,4,5])) ==> (map show [4,5,6]) ==> ["4","5","6"] Lazy: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) (filter (>2) [2,3,4,5]))) 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) [3,4,5])) ==> (map show [4,5,6]) ==> ["4","5","6"] Lazy: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) (filter (>2) [2,3,4,5]))) ==> (map show (map (+1) (filter (>2) [3,4,5]))) 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) [3,4,5])) ==> (map show [4,5,6]) ==> ["4","5","6"] Lazy: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) (filter (>2) [2,3,4,5]))) ==> (map show (map (+1) (filter (>2) [3,4,5]))) ==> "4" : (map show (map (+1) (filter (>2) [4,5]))) 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) [3,4,5])) ==> (map show [4,5,6]) ==> ["4","5","6"] Lazy: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) (filter (>2) [2,3,4,5]))) ==> (map show (map (+1) (filter (>2) [3,4,5]))) ==> "4" : (map show (map (+1) (filter (>2) [4,5]))) ==> "4" : "5" : (map show (map (+1) (filter (>2) [5]))) 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) [3,4,5])) ==> (map show [4,5,6]) ==> ["4","5","6"] Lazy: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) (filter (>2) [2,3,4,5]))) ==> (map show (map (+1) (filter (>2) [3,4,5]))) ==> "4" : (map show (map (+1) (filter (>2) [4,5]))) ==> "4" : "5" : (map show (map (+1) (filter (>2) [5]))) ==> "4" : "5" : "6" : (map show (map (+1) (filter (>2) [])) 15

Strict vs Lazy Evaluation Strict: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) [3,4,5])) ==> (map show [4,5,6]) ==> ["4","5","6"] Lazy: (map show. map (+1). filter (>2)) [1,2,3,4,5] ==> (map show (map (+1) (filter (>2) [1,2,3,4,5]))) ==> (map show (map (+1) (filter (>2) [2,3,4,5]))) ==> (map show (map (+1) (filter (>2) [3,4,5]))) ==> "4" : (map show (map (+1) (filter (>2) [4,5]))) ==> "4" : "5" : (map show (map (+1) (filter (>2) [5]))) ==> "4" : "5" : "6" : (map show (map (+1) (filter (>2) [])) ==> ["4","5","6"] 15

Infinite Data Structures zipwith :: (a -> b -> c) -> [a] -> [b] -> [c] 16

Infinite Data Structures zipwith :: (a -> b -> c) -> [a] -> [b] -> [c] zipwith f [] _ = [] zipwith f _ [] = [] zipwith f (x:xs) (y:ys) = f x y : zipwith f xs ys 16

Infinite Data Structures zipwith :: (a -> b -> c) -> [a] -> [b] -> [c] zipwith f [] _ = [] zipwith f _ [] = [] zipwith f (x:xs) (y:ys) = f x y : zipwith f xs ys fibs :: [Int] fibs = 0 : 1 : zipwith (+) fibs (tail fibs) 16

Infinite Data Structures fibs = 0 : 1 : zipwith (+) fibs (tail fibs) 17

Infinite Data Structures fibs = 0 : 1 : zipwith (+) fibs (tail fibs) take 3 fibs 17

Infinite Data Structures fibs = 0 : 1 : zipwith (+) fibs (tail fibs) take 3 fibs ==> take 3 THUNK 17

Infinite Data Structures fibs = 0 : 1 : zipwith (+) fibs (tail fibs) take 3 fibs ==> take 3 THUNK ==> take 3 (0 : THUNK) 17

Infinite Data Structures fibs = 0 : 1 : zipwith (+) fibs (tail fibs) take 3 fibs ==> take 3 THUNK ==> take 3 (0 : THUNK) ==> 0 : (take 2 THUNK) 17

Infinite Data Structures fibs = 0 : 1 : zipwith (+) fibs (tail fibs) take 3 fibs ==> take 3 THUNK ==> take 3 (0 : THUNK) ==> 0 : (take 2 THUNK) ==> 0 : 1 : (take 1 THUNK) 17

Infinite Data Structures fibs = 0 : 1 : zipwith (+) fibs (tail fibs) take 3 fibs ==> take 3 THUNK ==> take 3 (0 : THUNK) ==> 0 : (take 2 THUNK) ==> 0 : 1 : (take 1 THUNK) ==> 0 : 1 : 1 : (take 0 THUNK) 17

Infinite Data Structures fibs = 0 : 1 : zipwith (+) fibs (tail fibs) take 3 fibs ==> take 3 THUNK ==> take 3 (0 : THUNK) ==> 0 : (take 2 THUNK) ==> 0 : 1 : (take 1 THUNK) ==> 0 : 1 : 1 : (take 0 THUNK) ==> 0 : 1 : 1 : [] 17

Infinite Data Structures fibs = 0 : 1 : zipwith (+) fibs (tail fibs) take 3 fibs ==> take 3 THUNK ==> take 3 (0 : THUNK) ==> 0 : (take 2 THUNK) ==> 0 : 1 : (take 1 THUNK) ==> 0 : 1 : 1 : (take 0 THUNK) ==> 0 : 1 : 1 : [] After execution, fibs = 0 : 1 : 1 : THUNK 17

The Hair Shirt Simon Peyton Jones: Laziness kept Haskell honest 1 Laziness makes side effects completely unpredictable 1 http://research.microsoft.com/en-us/um/people/simonpj/papers/ haskell-retrospective/haskellretrospective.pdf 18

The Hair Shirt Simon Peyton Jones: Laziness kept Haskell honest 1 Laziness makes side effects completely unpredictable Thus, Haskell is still pure 1 http://research.microsoft.com/en-us/um/people/simonpj/papers/ haskell-retrospective/haskellretrospective.pdf 18

Lazy Lists are Control Structures var output = "" for (i <- 1 to 10) { output = output + i.tostring } vs (concat. take 10. map show) [1..] 19

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 20

Dude - where s my RAM?

Space Leaks and Laziness Recall foldl: foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (x:xs) = foldl f (f z x) xs 21

Space Leaks and Laziness Recall foldl: foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (x:xs) = foldl f (f z x) xs Summing a list: foldl (+) 0 [1..10] 21

Space Leaks and Laziness Recall foldl: foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (x:xs) = foldl f (f z x) xs Summing a list: foldl (+) 0 [1..10] ==> foldl (+) (0 + 1) [2..10] 21

Space Leaks and Laziness Recall foldl: foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (x:xs) = foldl f (f z x) xs Summing a list: foldl (+) 0 [1..10] ==> foldl (+) (0 + 1) [2..10] ==> foldl (+) ((0 + 1) + 2) [3..10] 21

Space Leaks and Laziness Recall foldl: foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (x:xs) = foldl f (f z x) xs Summing a list: foldl (+) 0 [1..10] ==> foldl (+) (0 + 1) [2..10] ==> foldl (+) ((0 + 1) + 2) [3..10] ==> foldl (+) (((0 + 1) + 2) + 3) [4..10] 21

Space Leaks and Laziness Recall foldl: foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (x:xs) = foldl f (f z x) xs Summing a list: foldl (+) 0 [1..10] ==> foldl (+) (0 + 1) [2..10] ==> foldl (+) ((0 + 1) + 2) [3..10] ==> foldl (+) (((0 + 1) + 2) + 3) [4..10]... ==> foldl (+) (((((0 + 1) + 2) + 3) + 4) +... 10) [] 21

Space Leaks and Laziness Recall foldl: foldl :: (a -> b -> a) -> a -> [b] -> a foldl f z [] = z foldl f z (x:xs) = foldl f (f z x) xs Summing a list: foldl (+) 0 [1..10] ==> foldl (+) (0 + 1) [2..10] ==> foldl (+) ((0 + 1) + 2) [3..10] ==> foldl (+) (((0 + 1) + 2) + 3) [4..10]... ==> foldl (+) (((((0 + 1) + 2) + 3) + 4) +... 10) [] Code to perform repeated additions takes much more space than the answer 21

Tools Strictness annotations 22

Tools Strictness annotations Don t be too tail-recursive: consider foldr: foldr :: (a -> b -> b) -> b -> [a] -> b foldr f z [] = z foldr f z (x:xs) = f x (foldr f z xs) 22

Tools Strictness annotations Don t be too tail-recursive: consider foldr: foldr :: (a -> b -> b) -> b -> [a] -> b foldr f z [] = z foldr f z (x:xs) = f x (foldr f z xs) Use lazy containers with strict contents 22

Laziness Summary ADVANTAGES CODE RE-USE by not committing to a strategy too early PERFORMANCE by not wasting work DISADVANTAGES PURITY is required SPACE USAGE is difficult to reason about DEBUGGERS are more difficult to implement 23

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 24

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 24

Overloading Ordering data Tree a = Empty Node (Tree a) a (Tree a) 24

Overloading Ordering data Tree a = Empty Node (Tree a) a (Tree a) insert :: Tree a -> a -> Tree a insert Empty x = Node Empty x Empty insert (Node l y r) x = if x <= y then Node (insert x l) y r else Node l y (insert x r) 24

Overloading Ordering data Tree a = Empty Node (Tree a) a (Tree a) insert :: Tree a -> a -> Tree a insert Empty x = Node Empty x Empty insert (Node l y r) x = if x <= y then Node (insert x l) y r else Node l y (insert x r) What does this mean? 24

In Scala abstract class Tree[A] case class Empty[A]() extends Tree[A] case class Node[A]( left: Tree[A], x : A, right: Tree[A] ) extends Tree[A]

In Scala abstract class Tree[A] case class Empty[A]() extends Tree[A] case class Node[A]( left: Tree[A], x : A, right: Tree[A] ) extends Tree[A] def insert[a <: Ordered[A]](t : Tree[A], x : A): Tree[A] = t match { case Empty() => Node(Empty(), x, Empty() case Node(l, y, r) => if (x <= y) Node(insert(l, x), y, r) else Node(l, y, insert(r, x)) }

Type Classes For a given type, provide: Operations on the type Default implementations of some operations data Ordering = LT EQ GT class Ord a where compare :: a -> a -> Ordering (>) :: a -> a -> Bool a > b = case compare a b of GT -> True _ -> False... 26

Type Class Constraints data Tree a = Empty Node (Tree a) a (Tree a) insert :: (Ord a) => Tree a -> a -> Tree a insert Empty x = Node Empty x Empty insert (Node l y r) x = if x <= y then Node (insert x l) y r else Node l y (insert x r) 27

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 28

Eq class Eq a where (==) : a -> a -> Bool x == y = not (x /= y) (/=) : a -> a -> Bool x /= y = not (x == y) 28

Eq class Eq a where (==) : a -> a -> Bool x == y = not (x /= y) (/=) : a -> a -> Bool x /= y = not (x == y) Default implementations: clients need only define enough! 28

Ord class (Eq a) => Ord a where compare :: a -> a -> Ordering (<), (<=), (>=), (>) :: a -> a -> Bool max, min :: a -> a -> a -- plus default methods... 29

Ord class (Eq a) => Ord a where compare :: a -> a -> Ordering (<), (<=), (>=), (>) :: a -> a -> Bool max, min :: a -> a -> a -- plus default methods... Superclass constraint: all Ord must have Eq 29

Under the Hood class Num a where (+), (*) :: a -> a -> a neg :: a -> a instance Num Int where (+) = addint (*) = mulint neg = negint instance Num Float where (+) = addfloat (*) = mulfloat neg = negfloat sumsquares :: (Num a) => a -> a -> a sumsquares x y = x * x + y * y

Under the Hood data NumD a = NumDict (a -> a -> a) (a -> a -> a) (a -> a) plus (NumDict p t n) = p times (NumDict p t n) = t neg (NumDict p t n) = n instance Num Int where (+) = addint (*) = mulint neg = negint instance Num Float where (+) = addfloat (*) = mulfloat neg = negfloat sumsquares :: (Num a) => a -> a -> a sumsquares x y = x * x + y * y

Under the Hood data NumD a = NumDict (a -> a -> a) (a -> a -> a) (a -> a) plus (NumDict p t n) = p times (NumDict p t n) = t neg (NumDict p t n) = n numint = NumDict addint mulint negint instance Num Float where (+) = addfloat (*) = mulfloat neg = negfloat sumsquares :: (Num a) => a -> a -> a sumsquares x y = x * x + y * y

Under the Hood data NumD a = NumDict (a -> a -> a) (a -> a -> a) (a -> a) plus (NumDict p t n) = p times (NumDict p t n) = t neg (NumDict p t n) = n numint = NumDict addint mulint negint numfloat = NumDict addfloat mulfloat negfloat sumsquares :: (Num a) => a -> a -> a sumsquares x y = x * x + y * y

Under the Hood data NumD a = NumDict (a -> a -> a) (a -> a -> a) (a -> a) plus (NumDict p t n) = p times (NumDict p t n) = t neg (NumDict p t n) = n numint = NumDict addint mulint negint numfloat = NumDict addfloat mulfloat negfloat sumsquares :: (Num a) -> a -> a -> a sumsquares x y = x * x + y * y

Under the Hood data NumD a = NumDict (a -> a -> a) (a -> a -> a) (a -> a) plus (NumDict p t n) = p times (NumDict p t n) = t neg (NumDict p t n) = n numint = NumDict addint mulint negint numfloat = NumDict addfloat mulfloat negfloat sumsquares :: (Num a) -> a -> a -> a sumsquares dict x y = plus dict (times dict x y) (times dict x y)

Under the Hood data NumD a = NumDict (a -> a -> a) (a -> a -> a) (a -> a) plus (NumDict p t n) = p times (NumDict p t n) = t neg (NumDict p t n) = n numint = NumDict addint mulint negint numfloat = NumDict addfloat mulfloat negfloat sumsquares :: (Num a) -> a -> a -> a sumsquares dict x y = plus dict (times dict x y) (times dict x y)

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 36

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 36

Computing with State Generating labels: let lastlab = ref (-1) newlabel () = lastlab :=!lastlab + 1 "label" + (!lastlab.tostring()) 36

Computing with State, Purely Return a new state after updating: startlabel = -1 newlabel old = let next = old + 1 ("label" ++ show next, next) 37

Computing with State, Purely Return a new state after updating: startlabel = -1 newlabel old = let next = old + 1 ("label" ++ show next, next) Easy to forget 37

Computing with State, Purely Return a new state after updating: startlabel = -1 newlabel old = let next = old + 1 ("label" ++ show next, next) Easy to forget Difficult to read 37

Computing with State, Purely Return a new state after updating: startlabel = -1 newlabel old = let next = old + 1 ("label" ++ show next, next) Easy to forget Difficult to read Risk of time travel 37

State as a Container data WithLabels a = Labeled (Int -> (a, Int)) 38

State as a Container data WithLabels a = Labeled (Int -> (a, Int)) only :: a -> WithLabels a only x = Labeled (\i -> (x, i)) 38

State as a Container data WithLabels a = Labeled (Int -> (a, Int)) only :: a -> WithLabels a only x = Labeled (\i -> (x, i)) get :: WithLabels Int get = Labeled (\i -> (i, i)) 38

State as a Container data WithLabels a = Labeled (Int -> (a, Int)) only :: a -> WithLabels a only x = Labeled (\i -> (x, i)) get :: WithLabels Int get = Labeled (\i -> (i, i)) set :: Int -> WithLabels () set i = Labeled (\j -> ((), i)) 38

State as a Container data WithLabels a = Labeled (Int -> (a, Int)) only :: a -> WithLabels a only x = Labeled (\i -> (x, i)) get :: WithLabels Int get = Labeled (\i -> (i, i)) set :: Int -> WithLabels () set i = Labeled (\j -> ((), i)) run :: Int -> WithLabels a -> a run i (Labeled comp) = fst (comp i) 38

State as a Container data WithLabels a = Labeled (Int -> (a, Int)) only :: a -> WithLabels a only x = Labeled (\i -> (x, i)) get :: WithLabels Int get = Labeled (\i -> (i, i)) set :: Int -> WithLabels () set i = Labeled (\j -> ((), i)) run :: Int -> WithLabels a -> a run i (Labeled comp) = fst (comp i) 38

Threading State step :: WithLabels a -> (a -> WithLabels b) -> WithLabels b

Threading State step :: WithLabels a -> (a -> WithLabels b) -> WithLabels b step (Labeled comp) next = Labeled (\i -> let (x, j) = comp i (Labeled cont) = next x in cont j)

Generating Labels, purely getlabel :: WithLabels String getlabel = get 40

Generating Labels, purely getlabel :: WithLabels String getlabel = get step (\i -> let lab = "label" ++ show i in set (i + 1) 40

Generating Labels, purely getlabel :: WithLabels String getlabel = get step (\i -> let lab = "label" ++ show i in set (i + 1) step (\() -> only lab)) 40

Generating Labels, purely getlabel :: WithLabels String getlabel = get step (\i -> let lab = "label" ++ show i in set (i + 1) step (\() -> only lab)) -- At REPL > run 0 (getlabel step (\ -> getlabel)) "label1" 40

Sugar to the rescue! The code getlabel :: WithLabels String getlabel = get step (\i -> let lab = "label" ++ show i in set (i + 1) step (\() -> only lab)) is much better when written: getlabel :: WithLabels String getlabel = do i <- get let lab = "label" ++ show i set (i + 1) return lab 42

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 43

Monads class Monad m where return : a -> m a (>>=) : m a -> (a -> m b) -> m b (>>) : m a -> m b -> m b x >> y = x >>= (\_ -> y) 43

Monads class Monad m where return : a -> m a (>>=) : m a -> (a -> m b) -> m b (>>) : m a -> m b -> m b x >> y = x >>= (\_ -> y) m has kind * -> * 43

Monads class Monad m where return : a -> m a (>>=) : m a -> (a -> m b) -> m b (>>) : m a -> m b -> m b x >> y = x >>= (\_ -> y) m has kind * -> * (>>=) looks like the Scala signature def flatmap[b](f: A => C[B]): C[B] 43

Monads class Monad m where return : a -> m a (>>=) : m a -> (a -> m b) -> m b (>>) : m a -> m b -> m b x >> y = x >>= (\_ -> y) m has kind * -> * (>>=) looks like the Scala signature def flatmap[b](f: A => C[B]): C[B] Laws: Left identity: return x >>= f f x 43

Monads class Monad m where return : a -> m a (>>=) : m a -> (a -> m b) -> m b (>>) : m a -> m b -> m b x >> y = x >>= (\_ -> y) m has kind * -> * (>>=) looks like the Scala signature def flatmap[b](f: A => C[B]): C[B] Laws: Left identity: return x >>= f f x Right identity: x >>= return x 43

Monads class Monad m where return : a -> m a (>>=) : m a -> (a -> m b) -> m b (>>) : m a -> m b -> m b x >> y = x >>= (\_ -> y) m has kind * -> * (>>=) looks like the Scala signature def flatmap[b](f: A => C[B]): C[B] Laws: Left identity: return x >>= f f x Right identity: x >>= return x Associativity: (x >>= f) >>= g x >>= (\i -> f i >>= g) 43

Desugaring do do x ==> x 44

Desugaring do do x ==> x do x rest ==> x >> do y 44

Desugaring do do x ==> x do x rest do i <- x rest ==> x >> do y ==> x >>= (\i -> do rest) 44

Desugaring do do x ==> x do x rest do i <- x rest ==> x >> do y ==> x >>= (\i -> do rest) do let i = x rest ==> let i = x in do rest 44

WithLabels is a Monad! instance Monad WithLabels where return = only (>>=) = step 45

Desugaring getlabel getlabel :: WithLabels String getlabel = do i <- get let lab = "label" ++ show i set (i + 1) return lab getlabel :: WithLabels String getlabel = get >>= (\i -> let lab = "label" ++ show i in set (i + 1) >> return lab) 46

Example Monads instance Monad [] where return x = [x] [] >>= f = [] (x:xs) >>= f = f x ++ (xs >>= f) 47

Example Monads instance Monad [] where return x = [x] [] >>= f = [] (x:xs) >>= f = f x ++ (xs >>= f) instance Monad Maybe where return x = Just x (Just x) >>= f = f x Nothing >>= f = Nothing 47

Example Monads instance Monad [] where return x = [x] [] >>= f = [] (x:xs) >>= f = f x ++ (xs >>= f) instance Monad Maybe where return x = Just x (Just x) >>= f = f x Nothing >>= f = Nothing instance Monad (Either a) where return x = Right x (Left err) >>= f = Left err (Right x) >>= f = f x 47

Monadic I/O I/O takes the world as a parameter and constructs a new world! 48

Monadic I/O Use a monad to thread the world through computation: data IO a = MkIO (World -> (a, World)) instance Monad IO where return x = MkIO (\w -> (x, w)) (MkIO x) >>= y = MkIO (\w -> let (res, newworld) = x w (MkIO cont) = y res in cont newworld) User code can t pattern-match MkIO it only has return and (>>=) so no shenanigans with the World. 49

Hello, world main :: IO () main = do putstrln "Who are you?" name <- getline putstrln ("Hello, " ++ name) 50

Hello, world main :: IO () main = do putstrln "Who are you?" name <- getline putstrln ("Hello, " ++ name) main :: IO () main = putstrln >>= (\ -> getline >>= (\name -> putstrln ("Hello, " ++ name))) Not a world in sight... 50

Monad Libraries mapm :: Monad m => (a -> m b) -> [a] -> m [b] mapm_ :: Monad m => (a -> m b) -> [a] -> m () 51

Monad Libraries mapm :: Monad m => (a -> m b) -> [a] -> m [b] mapm_ :: Monad m => (a -> m b) -> [a] -> m () sequence :: Monad m => [m a] -> m [a] sequence_ :: Monad m => [m a] -> m () 51

Monad Libraries mapm :: Monad m => (a -> m b) -> [a] -> m [b] mapm_ :: Monad m => (a -> m b) -> [a] -> m () sequence :: Monad m => [m a] -> m [a] sequence_ :: Monad m => [m a] -> m () when :: Monad m => Bool -> m () -> m () 51

Monads in.net LINQ is inspired by Haskell monads: public static IEnumerable<B> SelectMany<A, B>( this IEnumerable<A> source, Func<A, IEnumerable<B>> selector ) vs (>>=) :: m a -> (a -> m b) -> m b 52

Higher-Order Types at Work.NET loses type information Select and SelectMany return IEnumerable Monad preserves type information Being a monad is a property of type constructors, while being IEnumerable is a merely property of types. 53

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 54

Learn More RESOURCES Learn You a Haskell for Great Good https://www.fpcomplete.com/school Hoogle lets you search libraries by type PROJECT POSSIBILITIES Idris is an advanced open-source functional language with a compiler written in Haskell. We re a good source of projects! 54

Overview HELLO, WORLD BASIC SYNTAX LAZY EVALUATION Laziness Space Leaks TYPE CLASSES Overloading Examples GETTING THINGS DONE COMPUTING WITH STATE Monads in Haskell LEARN MORE WHAT S NEXT 55

What s Next Today, 13:00-13:50: Demonstration in Aud. 3 of starting project with fsyacc and fslex, from scratch (Ahmad is in 2A54) Spørgetime on Friday, December 20 from 10 AM to noon in Aud. 3 Exam: may need to be turned in on paper news to follow. Assignment deadline is Wednesday, December 4 55