Recursive Data Types Koen Lindström Claessen. Modelling Arithmetic Expressions Imagine a program to help school-children learn arithmetic, which presents.

Slides:



Advertisements
Similar presentations
1 Programming Languages (CS 550) Mini Language Interpreter Jeremy R. Johnson.
Advertisements

Chapter 7 Introduction to Procedures. So far, all programs written in such way that all subtasks are integrated in one single large program. There is.
More about functions Plus a few random things. 2 Tail recursion A function is said to be tail recursive if the recursive call is the very last thing it.
© M. Winter COSC 4P41 – Functional Programming Testing vs Proving Testing –uses a set of “typical” examples, –symbolic testing, –may find errors,
1 Programming Languages (CS 550) Lecture Summary Functional Programming and Operational Semantics for Scheme Jeremy R. Johnson.
CSE341: Programming Languages Lecture 16 Datatype-Style Programming With Lists or Structs Dan Grossman Winter 2013.
0 PROGRAMMING IN HASKELL Chapter 10 - Declaring Types and Classes.
String is a synonym for the type [Char].
Functional Programming Universitatea Politehnica Bucuresti Adina Magda Florea
Copyright © 2006 The McGraw-Hill Companies, Inc. Programming Languages 2nd edition Tucker and Noonan Chapter 14 Functional Programming It is better to.
Compiler Principle and Technology Prof. Dongming LU Mar. 28th, 2014.
Datastructures Koen Lindström Claessen (guest lecture by Björn Bringert)
Laziness and Infinite Datastructures Koen Lindström Claessen.
Modelling & Datatypes Koen Lindström Claessen. Software Software = Programs + Data.
Introduction to ML - Part 2 Kenny Zhu. What is next? ML has a rich set of structured values Tuples: (17, true, “stuff”) Records: {name = “george”, age.
Stacks (Revised and expanded from CIT 591). What is a stack? A stack is a Last In, First Out (LIFO) data structure Anything added to the stack goes on.
Stacks. 2 What is a stack? A stack is a Last In, First Out (LIFO) data structure Anything added to the stack goes on the “top” of the stack Anything removed.
CS510AP Quick Check Monads. QuickCheck Quick check is a Haskell library for doing random testing. You can read more about quickcheck at –
Bash Shell Scripting 10 Second Guide Common environment variables PATH - Sets the search path for any executable command. Similar to the PATH variable.
0 PROGRAMMING IN HASKELL Chapter 11 - Interactive Programs, Declaring Types and Classes.
PrasadCS7761 Haskell Data Types/ADT/Modules Type/Class Hierarchy Lazy Functional Language.
COMP Parsing 2 of 4 Lecture 22. How do we write programs to do this? The process of getting from the input string to the parse tree consists of.
Advanced Functional Programming 2009 Ulf Norell (lecture by Jean-Philippe Bernardy)
Interpretation Environments and Evaluation. CS 354 Spring Translation Stages Lexical analysis (scanning) Parsing –Recognizing –Building parse tree.
Review 1.Lexical Analysis 2.Syntax Analysis 3.Semantic Analysis 4.Code Generation 5.Code Optimization.
Chapter 9: Functional Programming in a Typed Language.
Lee CSCE 314 TAMU 1 CSCE 314 Programming Languages Haskell: Types and Classes Dr. Hyunyoung Lee.
Chapter 5 Control Structure (Repetition). Objectives In this chapter, you will: Learn about repetition (looping) control structures Explore how to construct.
COMP Parsing 3 of 4 Lectures 23. Using the Scanner Break input into tokens Use Scanner with delimiter: public void parse(String input ) { Scanner.
© M. Winter COSC 4P41 – Functional Programming Programming with actions Why is I/O an issue? I/O is a kind of side-effect. Example: Suppose there.
מבוא מורחב 1 Lecture #9. מבוא מורחב 2 Symbol: a primitive type constructors: (quote alpha) ==> quote is a special form. One argument: a name. selectors.
0 Odds and Ends in Haskell: Folding, I/O, and Functors Adapted from material by Miran Lipovaca.
Muhammad Idrees, Lecturer University of Lahore 1 Top-Down Parsing Top down parsing can be viewed as an attempt to find a leftmost derivation for an input.
Math, Data Types. Python Math Operations OperationOperator Addition + Subtraction – Multiplication * Division (floating point) / Division (integer) //
1 Programming Languages (CS 550) Lecture 2 Summary Mini Language Interpreter Jeremy R. Johnson.
CS Class 04 Topics  Selection statement – IF  Expressions  More practice writing simple C++ programs Announcements  Read pages for next.
1 Proving Properties of Recursive Functions and Data Structures CS 270 Math Foundations of CS Jeremy Johnson.
Advanced Functional Programming 2010
Operational Semantics of Scheme
Parsing 2 of 4: Scanner and Parsing
String is a synonym for the type [Char].
CSE341: Programming Languages Lecture 17 Implementing Languages Including Closures Dan Grossman Spring 2017.
Laziness and Infinite Datastructures
Basic Scheme February 8, 2007 Compound expressions Rules of evaluation
Koen Lindström Claessen
COMP261 Lecture 18 Parsing 3 of 4.
Koen Lindström Claessen
Theory of Computation Lecture 4: Programs and Computable Functions II
Programming Languages Dan Grossman 2013
September 4, 1997 Programming Languages (CS 550) Lecture 6 Summary Operational Semantics of Scheme using Substitution Jeremy R. Johnson TexPoint fonts.
Test Data Generators.
Koen Lindström Claessen
Proving Properties of Recursive Functions and Data Structures
Higher-Order Procedures
Mini Language Interpreter Programming Languages (CS 550)
CSE341: Programming Languages Lecture 17 Implementing Languages Including Closures Dan Grossman Autumn 2018.
Lecture 15 (Notes by P. N. Hilfinger and R. Bodik)
The Metacircular Evaluator
slides created by Marty Stepp
Type & Typeclass Syntax in function
PROGRAMMING IN HASKELL
Types and Classes in Haskell
PROGRAMMING IN HASKELL
CSE341: Programming Languages Lecture 17 Implementing Languages Including Closures Dan Grossman Spring 2016.
Lecture #9 מבוא מורחב.
SE1H421 Procedural Programming LECTURE 4 Operators & Conditionals (1)
6.001 SICP Interpretation Parts of an interpreter
PROGRAMMING IN HASKELL
CSE341: Programming Languages Lecture 17 Implementing Languages Including Closures Dan Grossman Spring 2019.
Presentation transcript:

Recursive Data Types Koen Lindström Claessen

Modelling Arithmetic Expressions Imagine a program to help school-children learn arithmetic, which presents them with an expression to work out, and checks their answer. What is (1+2)*3?8 Sorry, wrong answer! The expression (1+2)*3 is data as far as this program is concerned (not the same as 9!). How shall we represent it? A string?? What is ”1+2”++”3”? What is ”1+hello world**”?

Modelling Expressions Let’s design a datatype to model arithmetic expressions -- not their values, but their structure. An expression can be: a number n an addition a+b a multiplication a*b data Expr = Num |Add |Mul What information should we store in each alternative?

Modelling Expressions Let’s design a datatype to model arithmetic expressions -- not their values, but their structure. An expression can be: a number n an addition a+b a multiplication a*b data Expr = NumInteger |AddExpr Expr |MulExpr Expr A recursive data type !!

Examples data Expr = Num Integer | Add Expr Expr | Mul Expr Expr The expression:is represented by: 2Num 2 2+2Add (Num 2) (Num 2) (1+2)*3Mul (Add (Num 1) (Num 2)) (Num 3) 1+2*3Add (Num 1) (Mul (Num 2) (Num 3))

A Difference There is a difference between –17 :: Integer –Num 17 :: Expr Why are these different? –Can do different things with them –Some things only work for one of them –So, their types should be different

Quiz Can you define a function eval :: Expr -> Integer which evaluates an expression? Example:eval (Add (Num 1) (Mul (Num 2) (Num 3))) 7 Hint: Recursive types often mean recursive functions!

Quiz Can you define a function eval :: Expr -> Integer which evaluates an expression? eval (Num n) = eval (Add a b) = eval (Mul a b)= Use pattern matching: one equation for each case. A and b are of type Expr. What can we put here?

Quiz Can you define a function eval :: Expr -> Integer which evaluates an expression? eval (Num n) =n eval (Add a b) =eval a + eval b eval (Mul a b)=eval a * eval b Recursive types mean recursive functions!

Showing Expressions Expressions will be more readable if we convert them to strings. showExpr (Mul (Num 1) (Add (Num 2) (Num 3))) ”1*2+3” showExpr :: Expr -> String showExpr (Num n)= show n showExpr (Add a b)= showExpr a ++ ”+” ++ showExpr b showExpr (Mul a b)= showExpr a ++ ”*” ++ showExpr b

Quiz Which brackets are necessary?1+(2+3) 1+(2*3) 1*(2+3) What kind of expression may need to be bracketed? When does it need to be bracketed?

Quiz Which brackets are necessary?1+(2+3) 1+(2*3) 1*(2+3) What kind of expression may need to be bracketed? When does it need to be bracketed? NO! YES! NO! Additions Inside multiplications.

Idea Format factors differently: showExpr :: Expr -> String showExpr (Num n)= show n showExpr (Add a b)= showExpr a ++ "+" ++ showExpr b showExpr (Mul a b)= showFactor a ++ "*" ++ showFactor b showFactor :: Expr -> String ? showFactor :: Expr -> String showFactor (Add a b) = "("++showExpr (Add a b)++")" showFactor e = showExpr e

Making a Show instance instance Show Expr where show = showExpr data Expr = Num Integer | Add Expr Expr | Mul Expr Expr deriving ( Show, Eq )

(Almost) Complete Program questions :: IO ( ) questions = do rnd <- newStdGen let e = generate 10 rnd arbitrary putStr ("What is "++show e++"? ") ans <- getLine putStrLn (if read ans==eval e then "Right!" else "Wrong!") questions Opposite of show New random seed An expression generator—needs to be written What’s this? let: Give name to a result

Using QuickCheck Generators in Other Programs Debug.QuickCheck exports –generate :: Int -> StdGen -> Gen a -> a Size is used, for example, to bound Integers QuickCheck generator Size parameter for generation Random seed

Generating Arbitrary Expressions instance Arbitrary Expr where arbitrary = arbExpr arbExpr :: Gen Expr arbExpr = oneof [ do n <- arbitrary return (Num n), do a <- arbExpr b <- arbExpr return (Add a b), do a <- arbExpr b <- arbExpr return (Mul a b) ] Does not work! (why?) Generates infinite expressions!

Generating Arbitrary Expressions instance Arbitrary Expr where arbitrary = sized arbExpr arbExpr :: Int -> Gen Expr arbExpr s = frequency [ (1, do n <- arbitrary return (Num n)), (s, do a <- arbExpr s’ b <- arbExpr s’ return (Add a b)), (s, do a <- arbExpr s’ b <- arbExpr s’ return (Mul a b)) ] where s’ = s `div` 2 Size argument changes at each recursive call

Demo Main> questions What is -3*4*-1*-3*-1*-1? -36 Right! What is 15*4*( )? -640 Wrong! What is 0? 0 Right! What is (-4+13)*-9* ? dunno Program error: Prelude.read: no parse

The Program questions :: IO ( ) questions = do rnd <- newStdGen let e = generate 10 rnd arbitrary putStr ("What is "++show e++"? ") ans <- getLine putStrLn (if read ans==eval e then "Right!" else "Wrong!") questions failing ans == show (eval e) cannot fail

Reading Expressions How about a function –readExpr :: String -> Expr Such that –readExpr “12+173” = Add (Num 12) (Num 173) –readExpr “12+3*4” = Add (Num 12) (Mul (Num 3) (Num 4)) We see how to implement this in the next lecture

Symbolic Expressions How about expressions with variables in them? data Expr = Num Integer | Add Expr Expr | Mul Expr Expr | Var Name type Name = String Add Var and change functions accordingly

Gathering Variables It is often handy to know exactly which variables occur in a given expression vars :: Expr -> [Name] vars = ?

Gathering Variables It is often handy to know exactly which variables occur in a given expression vars :: Expr -> [Name] vars (Num n) = [] vars (Add a b) = vars a `union` vars b vars (Mul a b) = vars a `union` vars b vars (Var x) = [x] From Data.List; combines two lists without duplication

Evaluating Expressions We would like to evaluate expressions with variables. What is the type? eval :: Expr -> ? eval :: Table Name Integer -> Expr -> Int Table of values for variables eval :: Table Name Integer -> Expr -> Integer eval env (Num n) = n eval env (Var y) = fromJust (lookup y env) eval env (Add a b) = eval env a + eval env b eval env (Mul a b) = eval env a * eval env b

Symbolic Differentiation Differentiating an expression produces a new expression. We implement it as: diff :: Expr -> Name -> Expr diff (Num n) x = Num 0 diff (Var y) x | x==y = Num 1 | x/=y = Num 0 diff (Add a b) x = Add (diff a x) (diff b x) diff (Mul a b) x = Add (Mul a (diff b x)) (Mul b (diff a x)) Variable to differentiate wrt.

Testing differentiate Main> diff (Mul (Num 2) (Var “x”)) “x” 2*1+0*x Not quite what we expected! -- not simplified

What happens? d (2*x) = 2 dx differentiate (Mul (Num 2) (Var ”x”)) ”x” Add (Mul (Num 2) (differentiate (Var ”x”) ”x”)) (Mul (Var ”x”) (differentiate (Num 2) ”x”)) Add (Mul (Num 2) (Num 1)) (Mul (Var ”x”) (Num 0)) 2*1 + x*0 How can we make differentiate simplify the result?

“Smart” Constructors Define add :: Expr -> Expr -> Expr add (Num 0) b = b add a (Num 0) = a add (Num x) (Num y) = Num (x+y) add a b = Add a b By using add instead of Add, certain simplifications are performed when constructing the expression! more simplification is possible…

Testing add Main> Add (Num 2) (Num 5) 2+5 Main> add (Num 2) (Num 5) 7

Symbolic Differentiation Differentiating an expression produces a new expression. We implement it as: diff :: Expr -> Name -> Expr diff (Num n) x = Num 0 diff (Var y) x | x==y = Num 1 | x/=y = Num 0 diff (Add a b) x = add (diff a x) (diff b x) diff (Mul a b) x = add (mul a (diff b x)) (mul b (diff a x)) note

“Smart” Constructors -- mul How to define mul? mul :: Expr -> Expr -> Expr mul (Num 0) b = Num 0 mul a (Num 0) = Num 0 mul (Num 1) b = b mul a (Num 1) = a mul (Num x) (Num y) = Num (x*y) mul a b = Mul a b

Expressions Expr as a datatype can represent expressions –Unsimplified –Simplified –Results –Data presented to the user Need to be able to convert between these

An Expression Simplifier Simplification function –simplify :: Expr -> Expr simplify :: Expr -> Expr simplify e | null (vars e) = ? … You continue at the group exercises!

Testing the Simplifier arbExpr :: Int -> Gen Expr arbExpr s = frequency [ (1, do n <- arbitrary return (Num n)), (s, do a <- arbExpr s’ b <- arbExpr s’ return (Add a b)), (s, do a <- arbExpr s’ b <- arbExpr s’ return (Mul a b)), (1, do x <- elements [”x”,”y”,”z”] return (Var x))] where s’ = s `div` 2

Testing an Expression Simplifier (1) Simplification should not change the value prop_SimplifyCorrect e env = eval env e == eval env (simplify e) prop_SimplifyCorrect e (Env env) = eval env e == eval env (simplify e) Generate lists of values for variables

Testing an Expression Simplifier data Env = Env (Table Name Integer) deriving ( Eq, Show ) instance Arbitrary Env where arbitrary = do a <- arbitrary b <- arbitrary c <- arbitrary return (Env [(”x”,a),(”y”,b),(”z”,c)])

Testing an Expression Simplifier (2) Simplification should do a good job prop_SimplifyNoJunk e = noJunk (simplify e) where noJunk (Add a b) = not (isNum a && isNum b) && noJunk a && noJunk b... You continue at the group exercises!

Forthcoming Group Exercise Build and test an expression simplifier! I found many subtle bugs in my own simplifier! –Often simplifier goes into an infinite loop –Use verboseCheck instead of quickCheck (prints test case before every test, so you see them even if the test loops or crashes)

Summary Recursive data-types can take many forms other than lists Recursive data-types can model languages (expressions, natural languages, programming languages) Functions working with recursive types are often recursive themselves When generating random elements in recursive datatypes, think about the size

Next Time How to write parsers –readExpr :: String -> Expr Case study: example of other recursive datatype –a simple game: ”the zoo” –guessing animals using yes/no questions