Lecture 2:Data Types, Functional Patterns, Recursion, Polymorphism

Slides:



Advertisements
Similar presentations
CMSC 330: Organization of Programming Languages Tuples, Types, Conditionals and Recursion or “How many different OCaml topics can we cover in a single.
Advertisements

ML Lists.1 Standard ML Lists. ML Lists.2 Lists  A list is a finite sequence of elements. [3,5,9] ["a", "list" ] []  ML lists are immutable.  Elements.
Getting started with ML ML is a functional programming language. ML is statically typed: The types of literals, values, expressions and functions in a.
Functional Programming Universitatea Politehnica Bucuresti Adina Magda Florea
Using Types Slides thanks to Mark Jones. 2 Expressions Have Types: The type of an expression tells you what kind of value you might expect to see if you.
0 PROGRAMMING IN HASKELL Chapter 4 - Defining Functions.
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.
Introduction to ML Last time: Basics: integers, Booleans, tuples,... simple functions introduction to data types This time, we continue writing an evaluator.
Using Types Slides thanks to Mark Jones. 2 Expressions Have Types: The type of an expression tells you what kind of value you might expect to see if you.
0 PROGRAMMING IN HASKELL Typeclasses and higher order functions Based on lecture notes by Graham Hutton The book “Learn You a Haskell for Great Good” (and.
0 REVIEW OF HASKELL A lightening tour in 45 minutes.
Dan Johnson.  Functional language that started development in  Committee designed language  Pure and Lazy  Compiled or Interpreted  Named after.
Hello.java Program Output 1 public class Hello { 2 public static void main( String [] args ) 3 { 4 System.out.println( “Hello!" ); 5 } // end method main.
Chapter 9: Functional Programming in a Typed Language.
Functional Programming With examples in F#. Pure Functional Programming Functional programming involves evaluating expressions rather than executing commands.
1-Nov-15 Haskell II Functions and patterns. Data Types Int + - * / ^ even odd Float + - * / ^ sin cos pi truncate Char ord chr isSpace isUpper … Bool.
1 Functional Programming Lecture 6 - Algebraic Data Types.
A Second Look At ML 1. Outline Patterns Local variable definitions A sorting example 2.
Chapter 7 Selection Dept of Computer Engineering Khon Kaen University.
0 Odds and Ends in Haskell: Folding, I/O, and Functors Adapted from material by Miran Lipovaca.
1 CS 457/557: Functional Languages Lists and Algebraic Datatypes Mark P Jones Portland State University.
0 PROGRAMMING IN HASKELL Chapter 4 - Defining Functions.
Error Example - 65/4; ! Toplevel input: ! 65/4; ! ^^ ! Type clash: expression of type ! int ! cannot have type ! real.
Chapter SevenModern Programming Languages1 A Second Look At ML.
An introduction to functional programming using Haskell CENG242 –Recitation 1.
4 - Conditional Control Structures CHAPTER 4. Introduction A Program is usually not limited to a linear sequence of instructions. In real life, a programme.
0 PROGRAMMING IN HASKELL Typeclasses and higher order functions Based on lecture notes by Graham Hutton The book “Learn You a Haskell for Great Good” (and.
6-Jul-16 Haskell II Functions and patterns. Data Types Int + - * / ^ even odd Float + - * / ^ sin cos pi truncate Char ord chr isSpace isUpper … Bool.
Functional Programming
Polymorphic Functions
Haskell: Syntax in Functions
Conditional Expressions
Principles of programming languages 12: Functional programming
PROGRAMMING IN HASKELL
Types CSCE 314 Spring 2016.
ML: a quasi-functional language with strong typing
Expressions and Assignment
Theory of Computation Lecture 4: Programs and Computable Functions II
Haskell Chapter 2.
MPCS 51400: Functional Programming
Java Primer 1: Types, Classes and Operators
Functions and patterns
A lightening tour in 45 minutes
Debugging and Random Numbers
Variables and Primative Types
CSE 3302 Programming Languages
ITM 352 Expressions, Precedence, Working with Strings Class #5
PROGRAMMING IN HASKELL
A brief look at some of the new features introduced to the language
PROGRAMMING IN HASKELL
FP Foundations, Scheme In Text: Chapter 14.
PROGRAMMING IN HASKELL
CSE 341 Section 5 Winter 2018.
Type & Typeclass Syntax in function
PROGRAMMING IN HASKELL
Types and Classes in Haskell
CSCE 314: Programming Languages Dr. Dylan Shell
Chapter # 2 Part 2 Programs And data
Haskell Types, Classes, and Functions, Currying, and Polymorphism
Fundamentals of Functional Programming
Chapter8: Statement-Level Control Structures April 9, 2019
Functions and patterns
PROGRAMMING IN HASKELL
Introduction to Programming
Functions and patterns
PROGRAMMING IN HASKELL
Theory of Computation Lecture 4: Programs and Computable Functions II
PROGRAMMING IN HASKELL
Review Previously User-defined data types: records, variants
Presentation transcript:

Lecture 2:Data Types, Functional Patterns, Recursion, Polymorphism MPCS 51400: Functional Programming

Algebraic Data Types (ADTs) Haskell allows you to extend the type system with new types via algebraic data types, a type formed by combining other types. An ADT consists of zero or more data constructors: Data constructors can be thought of as a box with a fixed number of fields of a fixed type (“similar” to unions in C and C++). E.g.: data Rational = Rational Integer Integer deriving (Show) data : Keyword that introduces the declaration of a new type, which in this case is called Rational. Types and data constructors ALWAYS begin with a capital letter. Rational: We define data constructor Rational, which has a place for two Integer values, which represent the numerator and dominator respectively. deriving (Show) : Allows for the ADT to be printed naturally (more on that later..)

ADTs (Cont’d) ADTs can have more than just one data constructor by using a Pipe (“|”): data Complex = Rectangular Double Double | Polar Double Double deriving (Show) data Vector = Vec2 Double Double | Vec3 Double Double Double | Vec4 Double Double Double Double

ADTs creation Construction of a ADT involves using one of its data constructors along with the values for the constructor’s fields (if applicable): Prelude> let oneHalf = Rational 2 4 Prelude> oneHalf Rational 2 4 Prelude> let v1 = Vec3 3 3 4 Prelude> v1 Vec3 3.0 3.0 4.0

Ranges Lets say we wanted a list that contains the numbers 1 to 10. We could right it as: myList = [1,2,3,4,5,6,7,8,9,10] But writing out long lists can be tedious. Instead you can use ranges, which make lists that are arithmetic sequences of elements that can be enumerated. Use the syntax [low..high] to create a range: Prelude> [1..20]   [1,2,3,4,5,6,7,8,9,10]    Prelude> ['a'..'z']   "abcdefghijklmnopqrstuvwxyz"   Ranges can also have a a “step value” to increment a range by a certain amount ( [step, low..hight]). The first value in the list will begin at the step value: myEvenNumbersTo20 = [2,4..20] ==> [2,4,6,8,10,12,14,16,18,20] myMultiplesOfThreeTo20 = [3,6..20] ==> [3,6,9,12,15,18]

Ranges & Infinite Lists You can make lists infinite by not specifying an upper bound: numbers = [1..] evenNumbers = [2, 4..] Be careful entering infinite list into the ghci because you could get a infinite printout.

Pattern Matching Pattern matching is a way of matching values against patterns and when appropriate binding variables to successful matches (one of my favorite aspects of functional languages): Patterns: Undefined variables, numerical literals, list syntax, and data constructors. Allows for writing functions that can determine two or more possibilities based on which value it matches.

Pattern Matching Examples {- True if the Integer is 2 or 3, otherwise false-} isItTwoOrThree :: Integer -> Bool isItTwoOrThree 2 = True isItTwoOrThree 3 = True isItTwoOrThree _ = False *Main> isItTwoOrThree 3 True *Main> isItTwoOrThree 2 *Main> isItTwoOrThree 24 False The “_” represents the universal patter that never fails to match (i.e. “anything else” case).

Pattern Matching cases The order of pattern matches matters! The evaluation of pattern matching proceeds from top to bottom and left to right on each case. Thus, the following example always returns “False” because the universal pattern will always match isItTwoOrThreeAlwaysFalse :: Integer -> Bool isItTwoOrThreeAlwaysFalse _ = False isItTwoOrThreeAlwaysFalse 2 = True isItTwoOrThreeAlwaysFalse 3 = True Order patterns from most specific to least specific Normally, the compiler will throw a pattern match warning if the above case happens

Forgetting Pattern Cases What happens if we forget to match a case in our pattern? isItTwoOrThree :: Integer -> Bool isItTwoOrThree 2 = True isItTwoOrThree 3 = True The above example is considered an incomplete pattern because it cannot match any other data (i.e., all other integers except 2 and 3). Incomplete pattern matches applied to values that they cannot handle return a bottom, a non-value used to denote that the program cannot return a value or result. This problem causes the program to throw an exception, which if unhandled, makes the program fail.

Forgetting Pattern Cases Warning You can be notified at compile time when your patterns are non-exhaustive (i.e. they don’t handle every possible case) by turning on all warnings. Prelude> :set -Wall Thus, the following code will provide a non-exhaustive warning: isItTwoOrThreeBad :: Integer -> Bool isItTwoOrThreeBad 2 = True isItTwoOrThreeBad 3 = True Warning: Pattern match(es) are non-exhaustive In an equation for ‘isItTwoOrThreeBad’: Patterns not matched: #x with #x `notElem` [2#, 3#]

Pattern Matching Tuples You can pattern match on lists instead of using functions (such as “fst” and “snd” for two-tuples) to retrieve its contents: fstCom :: (Integer, Integer) -> Integer fstCom (x,y) = x sndCom :: (Integer, Integer) -> Integer sndCom (x,y) = y

Pattern Matching Tuples You can also break down inside a let expression: fstComLet :: (Integer, Integer) -> Integer fstComLet tup = let (x,_) = tup in x sndComLet :: (Integer, Integer) -> Integer sndComLet tup = let (_,y) = tup in y Use the “_” in for the components we don’t use in other expressions.

Pattern Matching Lists Pattern matching on lists can be done by using the “: “ operator, which matches on one element within the list and the rest of the list: x:xs ==> is common notation for retrieving the head of the list (x) and the remaining elements of the list minus the head (xs). listHead :: [Double] -> Double listHead [] = error "Can't not retrieve the head of an empty list" listHead (x:xs) = x

Pattern Matching Lists {- Drops the head element in the list -} dropHead :: [Double] -> [Double] dropHead [] = [] dropHead (_:xs) = xs {- Adds the first two elements in the list -} addFirstTwo :: [Double] -> Double addFirstTwo [] = error "Not enough elements" addFirstTwo (_:[]) = error "Not enough elements" addFirstTwo (x:y:xs) = x + y

As-patterns Convenient for allowing to name a pattern that can be used on the right-hand side of an expression: Use the “@“ symbol to give a name to the pattern. {- Tacks on the number two if the list has more than two elements -} tackOnTwo :: [Double] -> [Double] tackOnTwo s@(_:_:xs) = 2:s tackOnTwo l = l

Case Expressions Similar to case statements seen in imperative languages (C++, Java, C) but more powerful because case expressions can pattern match on types of expressions: Function pattern matching is syntactic sugar for a case expression where the matching is done at the beginning of the function. Case expressions allow you to pattern match in the middle of an expression. Syntax: case expression of pattern -> result                       pattern -> result                       ...   isEvenText :: Integer -> String isEvenText num = let message num parity = "The number" ++ show num ++ " is " ++ parity in case even num of True -> message num "even" False -> message num “odd"

ADTs & Pattern Matching You can pattern match on a ADT’s structure just like other types: data Complex = Rectangular Double Double | Polar Double Double deriving (Show) magnitude :: Complex -> Double magnitude (Rectangular real imaginary) = sqrt $ real^2 + imaginary^2 magnitude (Polar r theta) = r

Guards Guards allow two or more possible outcomes when writing functions. The return value of the function is dependent on the evaluation of the evaluation of the guard’s condition. Guard syntax is represented by pipes that follow a function's name and its parameters. They are mainly used for decomposing complex conditional expressions into more readable code. bmiDescription ::Double -> String bmiDescription bmi | bmi <= 18.5 = "Underweight" | bmi <= 25.0 = "Normal weight" | bmi <= 30.0 = "Overweight" | otherwise = “Obesity" “otherwise” is typically used as the last guard pattern. Otherwise is just another name for True and represents the catch-all guard.

Guards Use a where-clause to allow for declarations to be used within the guard clauses: taxBracketRate :: Double -> String taxBracketRate amount | inRange 0 9275 = "10%" | inRange 9275 37650 = "15%" | inRange 37650 91150 = "25%" | inRange 91150 190150 = "28%" | inRange 190150 413350 = "33%" | inRange 413350 415050 = "35%" | otherwise = "39.6%" where inRange minAmt maxAmt = amount >= minAmt && amount < maxAmt

Anonymous functions An anonymous function is a function without a name. It is written using lambda syntax represented by a backslash: Prelude> \x -> x + 2 :: Integer -> Integer Prelude> (\ x -> x + 2 ) 3 5 Here’s two ways to write the triple function: {- Named function -} triple :: Integer -> Integer triple x = x * 3 {- Anonymous function -} (\x -> x * 3) :: Integer -> Integer Why Anonymous functions? Mostly used as a function that is passed to a higher-order function (more on this next week) since in most cases that’s the only place you are going to use that particular function.

List Recursion Haskell like many other functional languages uses recursion to iterate over structures (e.g. lists) instead of looping constructs (e.g. for, while, do, etc.) How can we sum up the elements within the list or find the length of a list? Recursion length' [] = 0 sum' [] = 0 length' (_:xs) = 1 + length' xs sum' (x:xs) = x + sum' xs

List Recursion length’ and sum’ function from the previous slide is what we call natural recursion on the list structure: There's a natural correspondence between the equations we use to define length and the list constructors ([] and (:)). In the case where one of the constituent values of an argument (e.g., the cs in the second line above) has the same type as whole argument, we apply our top- level function to that value. © 2009–2016 Ravi Chugh, Stuart A. Kurtz

Polymorphism Polymorphism is the ability to implement expressions that can accept arguments and return results of different types without having to write variations on the same expression for each type. What if we wanted to use the (+) operator for all types of numbers: Integers, Double, and Floats? Well if we did not have polymorphism then we would have to write multiple functions that have the same addition code since we cannot mix types: sumFloat :: Float -> Float -> Float sumInt :: Int -> Int -> Int sumDouble :: Double -> Double -> Double Polymorphism makes programs easily extensible and facilitates rich libraries and common vocabularies.

Type Variables A type variable is a way to refer to an unspecified type or set of types in Haskell type signatures. They can be used to define polymorphic abstract data types: data Pair x y = Pair x y x and y are type variables (i.e. they can be represented by any concrete type): > Pair 1 "one" :: Pair Int String > Pair "one" 1.0 :: Pair String Double Type variables always begin with a lower-case letter.

Maybe Type Used to package either zero or one value of a given type. This type is useful for dealing with situations where we want to return "no result.”: data Maybe a = Nothing | Just a It is often preferable to denote "errors" explicitly using a Maybe value rather than implicitly with failure. This type is seen in many different functional languages (e.g. options in SML) and is becoming a feature built into more modern imperative languages (e.g., Swift - optional type). No more NULL!!!

Polymorphic functions Polymorphic functions are functions whose types include type variables. For example: length [] = 0 length (_:as) = 1 + length as What is the the type of length? Could be: [Int] -> Int or [Double] -> Int, etc… But what is the type of length inferred by Haskell? > :t length length :: [a] -> Int This means that length can take as input a list over any type, and compute its length.