cs252r : Advanced Functional Programming - Fall 2006
These pages are a record of the in-class discussions for the graduate class "Advanced Functional Programming" given at Harvard University in the Fall of 2006.November 13, 2006
- Lazy functional state threads. John Launchbury and Simon L. Peyton Jones.
If I have a Haskell term of type (forall a.a->a->a), what term do I have (you get three guesses)?
\x y -> x \x y -> y \x -> undefined \x y -> undefined undefined
If I have a ML term of type (forall a.a->a->a), what term do I have (you get three guesses)?
\x y -> x \x y -> y \x y -> let exception E in raise E f x y = f x y
Lots of the material in this paper should be familiar: monads, I/O, treatment of the world. Connections with constructor classes should be clear. So of the things that are here, what's old and what's new?
Old: Formal semantics for stateful computations, monads for encapsulating state.
New: Using rank-2 types in runST to protect state, definition of IO in terms of ST, use of language construct to avoid building a more powerful type system.
Look at the 6 bullets at the end of the introduction, and try to rank them (possibly in groups) according to how important each one is likely to be to future research in functional programming.
- 1. Maintaining referential transparency
- - Encapsulation of stateful computations (via parametric polymorphism)
- 2. Programmer can reason about efficiency
- - Mutable objects can be named
- 3. IO is not special
- - lazy evaluation of stateful computations
Hidden Mutation
The paper says ``it is possible to encapsulate stateful computations so that they appear to the rest of the program as pure (stateless) functions which are guaranteed by the type system to have no [hidden interactions] with other computations.'' The purpose of this question is to investigate this power.
There are several imperative data structures that use ``hidden mutation;'' among them are union/find trees with dynamic path compression, splay trees, and move-to-front lists. What they all have in common is a lookup operation that is purely functional in its input/output behavior but that uses mutable state to make subsequent lookups faster. Given that splay trees didn't make us so happy earlier in the term, we will work with move-to-front lists today. Ordinary list search works from front to back:
> find p [] = Nothing > find p (x:xs) | p x = Just x > find p (x:xs) = find p xs
To speed up later searches for matching elements, we can move them to the front of the list:
> moveToFront p l = List.filter p l ++ List.filter (not . p) l
Your mission is to use runST and friends to implement findFront, a function that searches a list while transparently moving found elements to the front. In doing so, answer these two questions:
Is it possible to make the stateful computation findFront appear pure to the rest of the program?
Yes.
findFront :: MutVars [a] -> (a -> Bool) -> ST s [a]
\l p -> runST $
do { l' <- newVar l
; findFront l' p
}
Is it possible to guarantee that findFront has no interactions with other computations (including possibly other calls to findFront on other lists)?
Yes, by not putting other computations that mutate state into the same state thread.
What argument is being made in Section 5.4 and why is it important?
What are the weak spots in the arguments being made in Section 6?
What are the limitations of the technology described in this paper?
BibTeX
@InProceedings{John-Launchbury-and-Simon-L.-Peyton-Jones1994
, isbn = "0-89791-662-X"
, author = "John Launchbury and Simon L. Peyton Jones"
, publisher = "ACM Press"
, title = "Lazy functional state threads"
, address = "New York, NY, USA"
, year = 1994
, url = "http://doi.acm.org/10.1145/178243.178246"
, pages = "24--35"
, booktitle = "Proceedings of the ACM SIGPLAN 1994 conference on Programming language design and implementation"
}