How to be a Productive Programmer by putting things ofg until tomorrow Robert Atkey University of Strathclyde, Glasgow, UK 11th November 2011
Playing in Streams co data Stream = StreamCons Integer Stream ones :: Stream ones = StreamCons 1 ones map :: ( Integer → Integer ) → Stream → Stream map f ( StreamCons x xs ) = StreamCons ( f x ) ( map f xs ) merge :: Stream → Stream → Stream merge ( StreamCons x xs ) ( StreamCons y ys ) = StreamCons x ( StreamCons y ( merge xs ys ))
Playing in Streams co data Stream = StreamCons Integer Stream ones :: Stream ones = StreamCons 1 ones map :: ( Integer → Integer ) → Stream → Stream map f ( StreamCons x xs ) = StreamCons ( f x ) ( map f xs ) merge :: Stream → Stream → Stream merge ( StreamCons x xs ) ( StreamCons y ys ) = StreamCons x ( StreamCons y ( merge xs ys ))
Higher-order Functions on Streams mergef :: ( Integer → Integer → Stream → Stream ) → Stream → Stream → Stream mergef f ( StreamCons x xs ) ( StreamCons y ys ) = f x y ( mergef f xs ys )
Higher-order Functions on Streams mergef :: ( Integer → Integer → Stream → Stream ) → Stream → Stream → Stream mergef f ( StreamCons x xs ) ( StreamCons y ys ) = f x y ( mergef f xs ys ) A bad choice of argument yields non-productive defjnitions: badf :: Integer → Integer → Stream → Stream badf x y s = s
Higher-order Functions on Streams mergef :: ( Integer → Integer → Stream → Stream ) → Stream → Stream → Stream mergef f ( StreamCons x xs ) ( StreamCons y ys ) = f x y ( mergef f xs ys ) Coq reports: Sub-expression “ f x y ( mergef f xs ys ) ” not in guarded form
Higher-order Functions on Streams mergef :: ( Integer → Integer → Stream → Stream ) → Stream → Stream → Stream mergef f ( StreamCons x xs ) ( StreamCons y ys ) = f x y ( mergef f xs ys ) Get around guardedness check by changing the type of f? f :: Integer → Integer → Integer f :: Integer → Integer → ( Integer , [ Integer ]) but what about: f x y s = StreamCons x ( map (+ 1 ) s )
How can we put guardedness constraints into the types?
(Nakano, 2000) (McBride, 2009) Putting things ofg until tomorrow
Putting things ofg until tomorrow (Nakano, 2000) (McBride, 2009)
Type-based Guardedness f :: Integer → Integer → ⊲ Stream → Stream
Type-based Guardedness f :: Integer → Integer → ⊲ Stream → Stream
ones fjx s 1 s fjx x x Type-based Guardedness ⊲ Stream “a stream tomorrow” − StreamCons :: Integer → ⊲ Stream → Stream deStreamCons :: Stream → ( Integer , ⊲ Stream ) fjx :: ( ⊲ A → A ) → A
Type-based Guardedness ⊲ Stream “a stream tomorrow” − StreamCons :: Integer → ⊲ Stream → Stream deStreamCons :: Stream → ( Integer , ⊲ Stream ) fjx :: ( ⊲ A → A ) → A ones = fjx ( λ s . StreamCons 1 s ) fjx ( λ x . x )
Type-based Guardedness ⊲ Stream “a stream tomorrow” − StreamCons :: Integer → ⊲ Stream → Stream deStreamCons :: Stream → ( Integer , ⊲ Stream ) fjx :: ( ⊲ A → A ) → A ones = fjx ( λ s . StreamCons 1 s ) fjx ( λ x . x ) ✘✘✘✘✘
mergef Integer Integer Stream Stream Stream Stream Stream mergef f fjx g xs ys let x xs’ xs let y ys’ ys in f x y g xs’ ys’ g Stream Stream Stream Applicative Functor pure :: A → ⊲ A ( ⊛ ) :: ⊲ ( A → B ) → ⊲ A → ⊲ B
Applicative Functor pure :: A → ⊲ A ( ⊛ ) :: ⊲ ( A → B ) → ⊲ A → ⊲ B mergef :: ( Integer → Integer → ⊲ Stream → Stream ) → Stream → Stream → Stream mergef f = fjx ( λ g xs ys . let ( x , xs’ ) = deStreamCons xs let ( y , ys’ ) = deStreamCons ys in f x y ( g ⊛ xs’ ⊛ ys’ )) g :: ⊲ ( Stream → Stream → Stream )
take 0 s take n 1 s x take n s’ where x s’ s This type prevents us: Stream Integer Stream We cannot leave the “time stream” of the stream. From Infjnite to Finite Can we write take :: Natural → Stream → [ Integer ] by structural recursion on the fjrst argument?
This type prevents us: Stream Integer Stream We cannot leave the “time stream” of the stream. From Infjnite to Finite Can we write take :: Natural → Stream → [ Integer ] by structural recursion on the fjrst argument? take 0 s = [] take ( n + 1 ) s = x : take n s’ where ( x , s’ ) = deStreamCons s
From Infjnite to Finite Can we write take :: Natural → Stream → [ Integer ] by structural recursion on the fjrst argument? take 0 s = [] take ( n + 1 ) s = x : take n s’ where ( x , s’ ) = deStreamCons s This type prevents us: deStreamCons :: Stream → ( Integer , ⊲ Stream ) We cannot leave the “time stream” of the stream.
Clock Variables
Integer Stream Stream Stream Integer Stream delay A A A B A B fjx A A A Clock Variables Annotate with “clock variables”, κ : ◮ A clock κ represents a fjxed amount of time remaining ◮ Stream κ is a stream for at least the time remaining in κ κ removes one unit of time remaining in κ ◮ ⊲
delay A A A B A B fjx A A A Clock Variables Annotate with “clock variables”, κ : ◮ A clock κ represents a fjxed amount of time remaining ◮ Stream κ is a stream for at least the time remaining in κ κ removes one unit of time remaining in κ ◮ ⊲ StreamCons κ :: Integer → ⊲ κ Stream κ → Stream κ deStreamCons κ :: Stream κ → ( Integer , ⊲ κ Stream κ )
fjx A A A Clock Variables Annotate with “clock variables”, κ : ◮ A clock κ represents a fjxed amount of time remaining ◮ Stream κ is a stream for at least the time remaining in κ κ removes one unit of time remaining in κ ◮ ⊲ StreamCons κ :: Integer → ⊲ κ Stream κ → Stream κ deStreamCons κ :: Stream κ → ( Integer , ⊲ κ Stream κ ) delay κ :: A → ⊲ κ A κ ( A → B ) → ⊲ κ A → ⊲ κ B ( ⊛ κ ) :: ⊲
Clock Variables Annotate with “clock variables”, κ : ◮ A clock κ represents a fjxed amount of time remaining ◮ Stream κ is a stream for at least the time remaining in κ κ removes one unit of time remaining in κ ◮ ⊲ StreamCons κ :: Integer → ⊲ κ Stream κ → Stream κ deStreamCons κ :: Stream κ → ( Integer , ⊲ κ Stream κ ) delay κ :: A → ⊲ κ A κ ( A → B ) → ⊲ κ A → ⊲ κ B ( ⊛ κ ) :: ⊲ fjx κ :: ( ⊲ κ A → A ) → A
Stream streams that go on forever Quantifjcation allows removal of delays: force A A Eternity in an Hour For type A with a free clock variable κ : ◮ Form the type ∀ κ. A ◮ A with all possible amounts of “time remaining”
Quantifjcation allows removal of delays: force A A Eternity in an Hour For type A with a free clock variable κ : ◮ Form the type ∀ κ. A ◮ A with all possible amounts of “time remaining” ( ∀ κ. Stream κ ) streams that go on forever ≈
Eternity in an Hour For type A with a free clock variable κ : ◮ Form the type ∀ κ. A ◮ A with all possible amounts of “time remaining” ( ∀ κ. Stream κ ) streams that go on forever ≈ Quantifjcation allows removal of delays: force :: ( ∀ κ. ⊲ κ A ) → ( ∀ κ. A )
take 0 s take n 1 s x take n force s’ where x s’ s From Infjnite to Finite, again Can we write take :: Natural → ( ∀ κ. Stream κ ) → [ Integer ] by structural recursion on the fjrst argument?
From Infjnite to Finite, again Can we write take :: Natural → ( ∀ κ. Stream κ ) → [ Integer ] by structural recursion on the fjrst argument? take 0 s = [] take ( n + 1 ) s = x : take n ( force s’ ) where ( x , s’ ) = deStreamCons s
Derivation Let Γ = s : ∀ κ. Stream κ κ ; Γ ⊢ s : ∀ κ. Stream κ κ ; Γ ⊢ s : Stream κ κ ; Γ ⊢ deStreamCons s : ( Integer , ⊲ κ Stream κ ) ; Γ ⊢ deStreamCons s : ∀ κ. ( Integer , ⊲ κ Stream κ ) ; Γ ⊢ deStreamCons s : ( Integer , ∀ κ. ⊲ κ Stream κ )
Replace-Min A classic example (Bird, 1984) replaceMin :: Tree → Tree replaceMin t = let ( t’ , m ) = replaceMinBody ( t , m ) in t’ where replaceMinBody ( Leaf x , m ) = ( Leaf m , x ) replaceMinBody ( Br l r , m ) = let ( l’ , m l ) = replaceMinBody l m let ( r’ , m r ) = replaceMinBody r m in ( Br l’ r’ , min m l m r )
trace A U B U A B replaceMin Tree Tree replaceMin t force trace replaceMinBody t With Clocks κ Integer ) → ( ⊲ κ Tree , Integer ) replaceMinBody :: ∀ κ. ( Tree , ⊲ replaceMinBody ( Leaf x , m ) = ( delay Leaf ⊛ m , x ) replaceMinBody ( Br l r , m ) = let ( l’ , m l ) = replaceMinBody l m let ( r’ , m r ) = replaceMinBody r m in ( delay Br ⊛ l’ ⊛ r’ , min m l m r )
trace A U B U A B replaceMin Tree Tree replaceMin t force trace replaceMinBody t With Clocks κ Integer ) → ( ⊲ κ Tree , Integer ) replaceMinBody :: ∀ κ. ( Tree , ⊲ replaceMinBody ( Leaf x , m ) = ( delay Leaf ⊛ m , x ) replaceMinBody ( Br l r , m ) = let ( l’ , m l ) = replaceMinBody l m let ( r’ , m r ) = replaceMinBody r m in ( delay Br ⊛ l’ ⊛ r’ , min m l m r )
trace A U B U A B replaceMin Tree Tree replaceMin t force trace replaceMinBody t With Clocks κ Integer ) → ( ⊲ κ Tree , Integer ) replaceMinBody :: ∀ κ. ( Tree , ⊲ replaceMinBody ( Leaf x , m ) = ( delay Leaf ⊛ m , x ) replaceMinBody ( Br l r , m ) = let ( l’ , m l ) = replaceMinBody l m let ( r’ , m r ) = replaceMinBody r m in ( delay Br ⊛ l’ ⊛ r’ , min m l m r )
Recommend
More recommend