Haskell II - University of Pennsylvania

Download Report

Transcript Haskell II - University of Pennsylvania

Haskell II Functions and patterns

6-May-20

Data Types

       Int + - * / ^ even odd Float + - * / ^ sin cos pi truncate Char ord chr isSpace isUpper … Bool && || not Lists : ++ head tail last init take Tuples fst snd Polymorphic: < <= == /= => > show

User-Defined Data Types

    User-defined data types data Color = Red | Blue toString Red = "red" toString Blue = "blue" data Tree a = Leaf a | Branch (Tree a) (Tree a)  Can be tricky to use

Assorted Syntax

 Comments are or { to -} - to end of line (these may be nested)  Types are capitalized, variables are not     Indentation may be used in place of braces Infix operators: + - `mod` `not` Prefix operators: Types: (+) (-) mod not take :: Int -> [a] -> [a]

Layout

 The first nonblank character following where , let , or of determines the starting column  let x = a + b y = a * b in y / x   If you start too far to the left, that may end an enclosing clause You can use { } instead, but this is not usually done

Infinite Lists

       [1..5] == [1, 2, 3, 4, 5] [1..] == all positive integers [5, 10..32] == [5, 10, 15, 20, 25, 30] [5, 10..] == positive multiples of 5 [x*x | x <- [1..]] == squares of positive ints [x*x | x <- [1..], even x] == squares of positive even ints [(x, y) | x <- [1..10], y <- [1..10], x < y]

Functions are also data

Functions are

first-class objects

”  Functions can be assigned  Functions can be passed as parameters  Functions can be stored in data structures   There are operations on functions But functions can ’ t be tested for equality  Theoretically very hard!

Anonymous Functions

    Form is \

parameters

->

body

Example:  the \  the x \x y -> (x + y) / 2 is pronounced “ lambda ” and y are the formal parameters inc x = x + 1  this is shorthand for inc = \x -> x + 1 add x y = x + y  this is shorthand for add = \x y -> x + y

Currying

 Technique named after Haskell Curry  Functions only need one argument    Currying absorbs an argument into a function f a b = (f a) b , where (f a) is a curried function (avg 6) 8  7.0

Slicing

    Functions may be “ partially applied ” inc x = x + 1  can be defined instead as inc = (+ 1) add x y = x + y  can be defined instead as add = (+) negative = (< 0)

map

 map :: (a -> b) -> [a] -> [b]    applies the function to all elements of the list Prelude> map odd [1..5]  [True,False,True,False,True] Prelude> map (* 2) [1..5]  [2,4,6,8,10]

filter

 filter :: (a -> Bool) -> [a] -> [a]    Returns the elements that satisfy the test Prelude> filter even [1..10]  [2,4,6,8,10] Prelude> filter (\x -> x>3 && x<10) [1..20]  [4,5,6,7,8,9]

iterate

    iterate :: (a -> a) -> a -> [a] f x returns the list [x, f x, f f x, f f f x, …] Prelude> take 8 (iterate (2 *) 1)  [1,2,4,8,16,32,64,128] Prelude> iterate tail [1..3]   [[1,2,3],[2,3],[3],[], *** Exception: Prelude.tail: empty list

foldl

   foldl :: (a -> b -> a) -> a -> [b] -> a foldl

f i x

starts with

i

, repeatedly applies

f

to

i

and the next element in the list

x

Prelude> foldl (-) 100 [1..3]   94 94 = 100 - 1 - 2 - 3

foldl1

    foldl1 :: (a -> a -> a) -> [a] -> a Same as: foldl f (head x) (tail x) Prelude> foldl1 (-) [100, 1, 2, 3]  94 Prelude> foldl1 (+) [1..100]  5050

flip

 flip :: (a -> b -> c) -> b ->a -> c     Reverses first two arguments of a function Prelude> elem 'o' "aeiou"  True Prelude> flip elem "aeiou" 'o'  True Prelude> (flip elem) "aeiou" 'o'  True

Function composition with (.)

    (.) :: (a -> b) -> (c -> a) -> (c -> b) (f . g) x is the same as f (g x) double x = x + x quadruple = double . double doubleFirst = (* 2) . head Main> quadruple 3 12 Main> doubleFirst [3..10] 6

span

 span :: (a -> Bool) -> [a] -> ([a], [a])    Break the lists into two lists  those at the front that satisfy the condition  the rest Main> span (<= 5) [1..10]  ([1,2,3,4,5],[6,7,8,9,10]) Main> span (< 'm') "abracadabra"  ("ab","racadabra")

break

 break :: (a -> Bool) -> [a] -> ([a], [a])   Break the lists into two lists  those at the front that fail the condition  the rest Main> break (== ' ') "Haskell is neat!"  ("Haskell"," is neat!")

Function Definition I

  Functions are defined with = fact n = if n == 0 then 1 else n * fact (n - 1)

Function Definition II

    Functions are usually defined by cases fact n | n == 0 = 1 | otherwise = n * fact (n - 1) fact n = case n of 0 -> 1 n -> n * fact (n - 1) These are “ the same ”

Function Definition III

  You can separate the cases with “ patterns ” fact :: Int -> Int -- not essential fact 0 = 1 fact n = n * fact (n - 1)  How does this work?

Pattern Matching

 Functions cannot in general be overloaded  But they can be broken into cases    Each case must have the same signature fact :: Int -> Int -- explicit signature fact 0 = 1 fact n = n * fact (n - 1) fact 5 won ’ t match the first, but will match the second

Pattern Types I

  A variable will match anything A wildcard, _ , will match anything, but you can ’ t use the matched value  A constant will match only that value  Tuples will match tuples, if same length and constituents match  Lists will match lists, if same length and constituents match  However, the pattern may specify a list of arbitrary length

Pattern Types II

   (

h

:

t

) will match a nonempty list whose head is

h

and whose tail is

t

second (h:t) = head t Main> second [1..5]  2

Pattern Types III

 “ As-patterns ” have the form

w

@

pattern

   When the

pattern

matches, the

w

matches the whole of the thing matched firstThree all@(h:t) = take 3 all Main> firstThree [1..10]  [1,2,3]

Pattern Types IV

   (

n

+

k

) matches any value equal to or greater than

k

;

n

is

k

less than the value matched silly (n+5) = n Main> silly 20  15  This is the only arithmetical pattern; it does not generalize to any other pattern

Advantages of Haskell

 Extremely concise  Easy to understand  no, really!

 No core dumps  Polymorphism improves chances of re-use  Powerful abstractions  Built-in memory management

Disadvantages of Haskell

 Unfamiliar  Slow  because compromises are less in favor of the machine

quicksort

quicksort [] = [] quicksort (x:xs) = quicksort [y | y <- xs, y < x] ++ [x] ++ quicksort [y | y <- xs, y >= x]

The End