26

Strong functional programming

Embed Size (px)

DESCRIPTION

These are the slides of the talk I gave at fp-syd, on Thursday, July, 19th 2012

Citation preview

Page 1: Strong functional programming
Page 2: Strong functional programming

Without ⊥ TuringComplet

e

Codata Comonad

Page 3: Strong functional programming

Life without ⊥

loop :: Int -> Intloop n = 1 + loop n

loop 0 = 1 + loop 0

0 = 1

Int( )⊥

Page 4: Strong functional programming

Life without ⊥

-- a function returning the first argumentfirst a b = a

-- with strict evaluationfirst 1 = ⊥ ⊥

-- with lazy evaluationfirst 1 = 1⊥

Simpler language design

Strict vs lazy

Page 5: Strong functional programming

Life without ⊥

-- will not match if (a, b) is ⊥first (a, b) = a

-- a bottom value can be "lifted” to a pair of bottom values( a, b) = ⊥ ⊥ ⊥

Simpler language design

Pattern matching

Page 6: Strong functional programming

Life without ⊥

True & True = TrueTrue & False = FalseFalse & True = FalseFalse & False = False

Simpler language design

& Operator

⊥ & y = ?x & = ?⊥

⊥ & y = ⊥x & = False if x = False⊥x & = otherwise⊥ ⊥

Page 7: Strong functional programming

Life without ⊥ Simpler language design

Reduction

a = trueif a then b else c ==> b

-- is there always a normal form?-- is it unique? (YES <=> Strongly “Church-Rosser”

Page 8: Strong functional programming

Life without ⊥

-- So far, so good

-- Not Turing complete!-- Non termination?

Page 9: Strong functional programming

Turing complete L Interpreter for L?

-- the interpretereval code input = result-- the interpreter breakerevil code = 1 + eval code code

-- by definition of eval + evil “number”eval 666 666 = evil 666-- by definition of evilevil 666 = 1 + (eval 666 666)-- 'evil 666' 0 = 1evil 666 = 1 + evil 666

Page 10: Strong functional programming

Not Turing Complete

-- The rules of termination

Page 11: Strong functional programming

Termination Complete case analysis

-- taking the first element of a listhead a :: List a a -> ahead Nil default = defaulthead (Cons a rest) default = a

data NonEmptyList a = NCons a (List a)

-- taking the first element of a non-empty listhead a :: NonEmptyList a -> ahead (NCons a rest) = a

Page 12: Strong functional programming

Termination Complete case analysis

-- Arithmetic operators?1 / 00 / 0

Page 13: Strong functional programming

Termination Non-covariant type recursion

data Silly a = Very (Silly a -> a)

bad a :: Silly a -> abad (Very f) = f (Very f)

-- infinite recursion, again…ouch :: aouch = bad (Very bad)

Page 14: Strong functional programming

Termination Structural recursion

factorial :: Nat -> Natfactorial Zero = 0factorial (Suc Zero) = 1

-- we recurse with a sub-component of (Suc n)factorial (Suc n) = (Suc n) * (factorial n)

Page 15: Strong functional programming

Termination Structural recursion

-- Ackermann functionack :: Nat Nat -> Natack 0 n = n + 1

-- m + 1 is a shortcut for (Suc m)ack (m + 1) 0 = ack m 1ack (m + 1) (n + 1) = ack m (ack (m + 1) n)

-- every provably terminating function-- with first-order logic => a lot

Page 16: Strong functional programming

Termination Structural recursion

-- Naive power functionpow :: Nat -> Nat ->pow x n = 1, if n == 0 = x * (pow x (n - 1)), otherwise

-- Fasterpow :: Nat -> Nat -> Natpow x n = 1, if n == 0 = x * pow (x * x) (n / 2), if odd n = pow (x * x) (n / 2), otherwise

Page 17: Strong functional programming

Termination Structural recursion

-- representation of a binary digitdata Bit = On | Off-- built-inbits :: Nat -> List Bit

-- primitive recursive nowpow :: Nat -> Nat -> Natpow x n = pow1 x (bits n)

pow1 :: Nat -> List Bit -> Natpow1 x n = 1pow1 x (Cons On r) = x * (pow1 (x * x) r)pow1 x (Cons Off r) = pow1 (x * x) r

Page 18: Strong functional programming

Codata for“infinite” computations

-- How to program an OS?

Page 19: Strong functional programming

Codata A new keyword

-- in SFP-- (Cocons a rest) is in normal formcodata Colist a = Conil | a <> Colist a

-- in Haskelldata Stream a = Cons a (Stream a)

Page 20: Strong functional programming

Codata A new rule

-- functions on codata must always use a -- coconstructor for their resultfunction a :: Colist a -> Colist afunction a <> rest = 'xxx' <> (function ’yyy’)

-- looks familiar I suppose?ones :: Colist Natones = 1 <> ones

fibonacci :: Colist Natfibonacci = f 0 1 where f a b = a <> (fibonacci b (a + b))

Page 21: Strong functional programming

Codata A new proof mode

-- iterate a function: -- x, f x, f (f x), f (f (f x)),...iterate f x = x <> iterate f (f x)

-- map a function on a colistcomap f Conil = Conilcomap f a <> rest = (f a) <> (comap f rest)

-- can you prove that?iterate f (f x) = comap f (iterate f x)

Page 22: Strong functional programming

Codata A new proof mode

iterate f (f x) -- 1. by definition of iterate= (f x) <> iterate f (f (f x)) -- 2. by hypothesis= (f x) <> comap f (iterate f (f x))

-- 3. by definition of comap= comap f (x <> iterate f (f x))

-- 4. by definition of iterate= comap f (iterate f x)

Bisimilarity!

Page 23: Strong functional programming

Codata Limitations

-- not primary corecursive, but okevens = 2 <> (comap (+2) evens)

-- infinite listscodata Colist a = a <> Colist a

cotail a :: Colist a -> Colist acotail a <> rest = rest

-- don't do this at homebad = 1 <> (cotail bad)

Count coconstructors!

Page 24: Strong functional programming

A co-era is opening

extract :: W a -> acobind :: W a -> b -> W a -> W b

Page 25: Strong functional programming

Comonad A simple example

-- a Colist of Natsnats = 0 <> comap (+1) nats

-- take the first 2 elements of a ColistfirstTwo a :: Colist a -> (a, a)firstTwo a <> b <> rest = (a, b)

-- cobind firstTwo to natscobind firstTwo nats = (0, 1) <> (1, 2) <> (2, 3) <> …

Page 26: Strong functional programming

Costate Intuitions

-- State-- “return a result based on an observable state”-- thread mutable stateState (s -> (s, a))

-- Costate-- “return a result based on the internal state and an external event”-- aka ‘an Object’, ‘Store’Costate (e, e -> a)