Using Idris to Model State Machine of Open-Close Door - state-machine

At ScalaWorld 2015, Edwin Brady gave an exciting talk on Idris - https://www.youtube.com/watch?v=X36ye-1x_HQ.
In one of the examples, I recall that he showed how to use Idris to write a program representing a Finite State Machine (FSM) - for opening and closing a door. His
FSM may be a bit more complex, but, given the following states:
data DoorState = DOpen | DClosed
data DoorAction = Open | Close
I wrote a function that, given a DoorAction and DoorState, returns the new DoorState.
runDoorOp : DoorAction -> DoorState -> DoorState
runDoorOp Close DOpen = DClosed
runDoorOp Open DClosed = DOpen
But, the above function is partial, example: runDoorOp Open DOpen would crash.
I thought of using an Either or Maybe data type, but I think (from hearing that talk) that it's possible to encode this FSM in a type-safe way without Either/Maybe.
What's the idiomatic, Idris way to write the above function using path-dependent types, not using Maybe/Either?

A common strategy to represent these finite state machines is to define the states as an enumeration (which is precisely what your DoorState does!)
data DoorState = DOpen | DClosed
And then describe the valid transitions by defining a relation (think: DoorAction a b means that from a I'm allowed to go to b). As you can see the indices of the constructor Open are enforcing that you may only open a door if it's currently Dclosed and it'll become DOpen.
data DoorAction : DoorState -> DoorState -> Type where
Open : DoorAction DClosed DOpen
Close : DoorAction DOpen DClosed
From there on you can describe well-formed sequences of interactions with a door by making sure that whenever you try to apply an action, it is allowed by the state the system is in:
data Interaction : DoorState -> DoorState -> Type where
Nil : Interaction a a
Cons : DoorAction a b -> Interaction b c -> Interaction a c
In Edwin's talk the situation is more complex: the actions on the door are seen as side effects, opening the door may fail (and so it's not necessarily true that we have Open : DoorAction DClosed DOpen) but the core ideas are the same.
An interesting article you may want to have a look at is McBride's Kleisli arrows of outrageous fortune. In it, he is dealing with the same sort of systems equipped with an internal finite state machine in Haskell.

Related

How can I Implement Statecharts in Haskell? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
After having read the excellent book "Practical UML Statecharts in
C/C++" by Miro Samek, I am eager to try them out sometime. More
recently, I have started to teach myself Haskell and functional
programming.
Only a few chapters into my book on Haskell, it struck me that
statecharts might be difficult, and even against the grain of Haskell. After all, a large effort
goes into creating state-free programs, or at least keeping all impure
parts of the code well separated from the pure ones.
When I searched for "Haskell" combined with "statechart" on the net, I
found almost nothing! This piqued my curiosity. Haskell is, after all, a
reasonably old, general purpose programming language. How could it be
that there seems to be virtually no activity related to statecharts?
Several possible explanations were suggested in the Haskell sub-Reddit
thread "haskellers thoughts on statecharts", and I hope my short
excerpts won't warp the views of any of the authors:
/…/ the Haskell community in general is not very active in UI
development /…/
/…/ The downside of Statecharts is that all that flexibility
that they provide make modelchecking (and therefor also model-based
testing) harder. /…/
/…/ A state machine is a collection of states and transition
rules. But for implementation states are redundant, you can work with
transition rules alone, which are neatly represented as (a mutually
recursive family of) functions. /…/ But Haskell is free from this
restriction, so implementing state machine explicitly is usually
redundant.
Hense (sic!), as a Haskeller I don't really need explicit state
machine most of time. Functions as first-class citizens and TCO make
them an implementation detail at best and unneeded at worst. /…/
a. /…/ You're probably more lucky with search-terms like
"transition system", "actor model" or "state transducer" in the
Haskell ecosystem. /…/
b. /…/ Functional reactive programming (FRP) and arrows are ways of
implementing signal flow in Haskell. /…/
c. /…/ The State monad transformer can model that. If you have
external signals in an intermediate step, you can embed it in a
continuation monad. /…/
I allow myself to interpret, and comment this a bit:
I find the notion that H. programmers don't use statecharts since
they don't do that kind of programming a bit hard to believe. I may
be wrong, but I would think the field of application is much broader
than just UIs.
This argument is slightly above my head. The author perhaps focuses
on a certain type of testing, a certain tool. I mean, wouldn't a
well-defined set of states, up front, make testing a lot easier, if
anything?
This is perhaps the most interesting argument, that explicit states
would be superfluous in Haskell, and hence the need to code visible
state machines. My objection is perhaps unfair, but wasn't the state
machine abstraction (or rather, its visible incarnation in code)
invented in order to make things clearer and easier to understand?
The problem it solves — to make the unspecified, de facto state
machine hidden in "ordinary" programs, making decisions based on the
value of a large number of poorly organised variables, more visible
— isn't this negated by getting rid of the state machine?
Could it really be this simple, that statecharts are there, but are
simply called something completely different? … or are these
better solutions for the same problem, in the world of Haskell,
effectively making statecharts genuinely redundant?
Will all this become embarrassingly obvious once I have finished reading the book on Haskell and FP?
You could do it with state charts, but you don't need to because Haskell works at a higher level than other languages, and subsumes the state chart design into code. Here is how you do it. (Note: I'm simplifying this down from a monad transformer version which also handles exceptions, so sorry if I've made any mistakes)
First, you can define a state machine in Haskell like this:
newtype AutoS i o = AutoS {runAutoS :: (o, i -> AutoS i o)}
In other words a state machine consists of its latest output o and a function from an input i to the next state. I've called it "Auto" because these are automata, which is maths jargon for state machines.
Now you could just take a UML state chart and translate it directly into a collection of AutoS values. But there is a better way.
newtype Auto i o a = Auto {runAuto :: (a -> AutoS i o) -> AutoS i o}
This is a variation on the continuation monad. With a conventional monad the result from each step is used as the argument to the next, but in continuations each step gets the next step as a function argument and passes its result to that function. That sounds like a weird way of doing things, but it means that you get access to the "rest of the computation" from within the monad, which lets you do some clever things. But before explaining that, here are the instances. It's worth spending a bit of time meditating on the Monad instance in particular. In all these functions k is the continuation; the parameter representing the rest of the computation.
instance (Functor m) => Functor (Auto i o) where
fmap f (Auto act) = Auto $ \k -> act (k . f)
instance (Monad m) => Applicative (Auto i o ) where
pure v = Auto $ \k -> k v
f <*> v = Auto $ \k -> runAuto f $ \g -> runAuto v (k . g)
instance (Monad m) => Monad (Auto i o) where
return = pure
v >>= f = Auto $ \k -> runAuto v $ \x -> runAuto (f x) k
So now we can write actions in Auto. But what can they do? Here is the yield function, which is the only primitive in Auto:
yield :: o -> Auto i o i
yield v = Auto $ \k -> AutoS (v, k)
This is the magic bit. Like before, k is the continuation (i.e. everything that follows this step). Remember that the result of the step (i.e. the result of yield) gets passed to this function. By wrapping it up in an AutoS with the yielded value we are passing that value as the output of the state machine and giving the state machine caller the next state transition.
So now instead of writing a program as a state machine with lots of named states we can just write monadic code. When our monadic code wants to exchange information with the rest of the world it uses yield to send out a value and get a new one in return.
There is an old joke about a mathematician who is asked to capture a lion in a cage. The mathematician gets into the cage, closes the door, and declares (by a geometric inversion) that he is now outside the cage and everything else, lion included, is inside the cage. This continuation monad is a bit like that; your monadic code is like the mathematician; it passes a value into yield and gets a result back out. But from the point of view of the rest of the world the yielded value comes out of the state machine (the cage), and the next state transition goes back in to become the result of yield.
The only other thing you need here is a way to run an Auto action:
startMachine :: Auto i o Void -> AutoS i o
startMachine act = runAuto act $ error "Can't happen: Auto terminated."
This assumes that your state machines have no end state. You get Void from the void package. If you need an end state then it has to have a separate type and that type has to tramp around along with everything else. In the original Cont continuation monad that type is r.
The big advantage of doing this way is that the logic of the state machine is expressed as a sequence of steps just like a normal program. Without the monadic approach all you have is a list of states and transitions, which makes following the logic very hard. Its like reading a program where every line ends in a GOTO. When the code is incomprehensible you have to use a design notation to explain it. State charts are a bit like a flow chart for state machines. By using a monad you can program directly at the state chart level, rendering it irrelevant in exactly the same way that structured programming rendered flow charts irrelevant.
Creating a monad transformer version AutoT is left as an exercise for the student. Hint: newtype AutoS i o m = runAutoS :: m (o, i -> AutoS i o m)}, and then take a look at ContT in the monad transformer package.
Actually you could do this by replacing Auto with Cont. I didn't because I also needed exceptions and ContT doesn't do exceptions. Adding something like proper exception handling is also left as an exercise for the student. Hint: newtype AutoS i o e m = AutoS {runAutoS :: m (o, i -> AutoS i o e m, e -> AutoS i o e m) }
Edit: You mentioned the ease of testing the implementation of a state chart.
Yes, for a sufficiently small value of "test". If you implement a state chart in a conventional language using states indexed by an enumeration then testing that your state transitions match the state chart is indeed trivial. However you still need to verify that the state chart in your design was correct. This is exactly the same problem as verifying that monadic code in Auto is correct because they are both describing the solution at the same level of abstraction.

Parameter names of a function using a functional language such as F#

I have read a book called Clean code. One of the strongest messages that I took from the book is that the code must be readable. I do not understand why functional languages such as F# do not include function parameter names into the intellisense or in the type defintion?
Compare
val copy: string -> string -> unit
with
val copy: sourceFile:string -> destinationFile:string -> unit
What is the best practise in the functional world? Shall we prefer single parameter functions? This is what Clean code promotes. Or shall we use records for all functions of 2+ parameters?
I know that one work-around is to use static member instead of let functions but this is not a functional approach, is it?
EDIT:
Just to give more information:
Haskell : addThree :: Int -> Int -> Int -> Int
OCaml: Unix.unlink: (string -> unit)
and surely others. They just do not show parameter names in the type definitions.
If you practice typeful programming, which is the idea that a lot of the semantic content of programs can be reflected statically in the type system, you will find out that in many (but not all) cases, named arguments are not necessary for readability.
Consider the following examples in the List standard library of OCaml. By knowing that they operate on lists, and with the (hopefully clear: we're all for good name choices) name of the function, you will find that you don't need explanations for what the arguments do.
val append : α list -> α list
val flatten : α list list -> α list
val exists: (α -> α bool) -> α list -> bool
val map: (α -> β) -> α list -> β list
val combine : α list -> β list -> (α * β) list
Note that the last example is interesting because it is not exactly clear what the code will do. There would in fact be several interpretations. combine [1;2] [3;4] returns [(1,3); (2,4)] and not, for example, [(1,3); (1,4); (2,3); (2,4)]. It is also not clear what happens when the two lists are not of the same length (the failure mode is unclear).
Functions that are not total, that may raise an exception or not terminate, usually need more documentation about what the failure cases are and how they will behave. This is one strong argument in favor of what we call pure programming, where all the behavior of a function is expressed in terms of returning a value (no exceptions, observable state mutation, or non-termination), and can therefore be statically captured by the type system.
Of course this only works really well for functions that are parametric enough; they have a type that make it very clear what they do. This is not the case of all functions, consider for example the blit function of the String module (I'm sure your favorite language has such examples as well):
val blit : string -> int -> string -> int -> int -> unit
huh?
Programming languages add support named parameters for this reason. In OCaml for example we have "labels" that allow to name parameters. The same function is exported in the StringLabels module as:
val blit : src:string -> src_pos:int -> dst:string -> dst_pos:int -> len:int -> unit
That's better. Yes, named parameters are useful in some cases.
Note however that named arguments can be used to hide bad API design (maybe the example above is targe to this criticism as well). Consider:
val add : float -> float -> float -> float -> float -> float -> float * float * float
obscure, huh? But then:
type coord = {x:float; y:float; z:float}
val add : coord -> coord -> coord
That's much better, and I didn't need any parameter labeling (arguably record labels provide naming, but in fact I could equally use float * float * float here; the fact that value records may subsume named (and optionals?) parameters is also an interesting remark).
David M. Barbour develops the argument that named parameters are a "crutch" of language design, that is used to tamper over the lazyness of API designers, and that not having them encourages better design. I am not sure I agree that named parameters can be profitably avoided in all situations, but he certainly has a point that agrees with the typeful propaganda at the beginning of my post. By raising the level of abstraction (through more polymorphic/parametric types or better problem domain abstractions), you'll find you decrease the need for parameter naming.
Haskell's type synonyms can help in making the type signatures more self-documenting. Consider for example the function writeFile, that just writes a string to a file. It has two parameters: the string to write, and the filename to write to. Or was it the other way around? Both parameters are of type String, so it's not easy to tell which is which!
However, when you look at the documentation, you see the following type signature:
writeFile :: FilePath -> String -> IO ()
That makes it clear (to me, at least!) how the function is intended to be used. Now, since FilePath is just a synonym for String, there's nothing preventing you from using it like this:
writeFile "The quick brown fox jumped over the lazy dog" "test.txt"
but if you get the type FilePath -> String -> IO () as a hint in your IDE, I think that's at least a big push in the right direction!
You could even go a step further and make a newtype for filepaths so you don't accidentally mix up filenames and contents, but I guess that adds more hassle than it's worth, and there's probably also historical reasons why this isn't done.
Or am I completely wrong and it has nothing to do with diferences between functional and imperative programming?
You're not completely wrong, insofar as functional languages with HM type inference often do not require type annotations at all, or, at least not everywhere.
Add to this that type expressions are not necessarily function types, hence the concept of a "parameter name" is not applicable. All in all, a name there is just redundant, it does not add any information to a type, and that could be the reason for not allowing it.
Conversely, in imperative languages, type inference was almost unknown as of late. Thus you must declare everything (in statically typed languages) and so it happens that name and type tend to appear in one place. Moreover, as functions are not first class citiziens, the concept of a function type, let alone an expression that describes a function type is merely unknown.
Observe that with recent developments (like "lambda" syntax, etc.) the concept of an argument whose type is known already or can be easily inferred also appears in those languages. And when I remember correctly, there is even syntactical easement to avoid long names, the lambda argument is just it or even _
What is the best practise in the functional world?
There is alternative standard library for OCaml called Core. It uses labeled parameters almost everywhere. For example
val fold_left : 'a t -> init:'b -> f:('b -> 'a -> 'b) -> 'b
P.S. I have no information about another functional languages.

What other ways can state be handled in a pure functional language besides with Monads?

So I started to wrap my head around Monads (used in Haskell). I'm curious what other ways IO or state can be handled in a pure functional language (both in theory or reality). For example, there is a logical language called "mercury" that uses "effect-typing". In a program such as haskell, how would effect-typing work? How does other systems work?
There are several different questions involved here.
First, IO and State are very different things. State is easy to do
yourself: Just pass an extra argument to every function, and return an extra
result, and you have a "stateful function"; for example, turn a -> b into
a -> s -> (b,s).
There's no magic involved here: Control.Monad.State provides a wrapper that
makes working with "state actions" of the form s -> (a,s) convenient, as well
as a bunch of helper functions, but that's it.
I/O, by its nature, has to have some magic in its implementation. But there are
a lot of ways of expressing I/O in Haskell that don't involve the word "monad".
If we had an IO-free subset of Haskell as-is, and we wanted to invent IO from
scratch, without knowing anything about monads, there are many things we might
do.
For example, if all we want to do is print to stdout, we might say:
type PrintOnlyIO = String
main :: PrintOnlyIO
main = "Hello world!"
And then have an RTS (runtime system) which evaluates the string and prints it.
This lets us write any Haskell program whose I/O consists entirely of printing
to stdout.
This isn't very useful, however, because we want interactivity! So let's invent
a new type of IO which allows for it. The simplest thing that comes to mind is
type InteractIO = String -> String
main :: InteractIO
main = map toUpper
This approach to IO lets us write any code which reads from stdin and writes to
stdout (the Prelude comes with a function interact :: InteractIO -> IO ()
which does this, by the way).
This is much better, since it lets us write interactive programs. But it's
still very limited compared to all the IO we want to do, and also quite
error-prone (if we accidentally try to read too far into stdin, the program
will just block until the user types more in).
We want to be able to do more than read stdin and write stdout. Here's how
early versions of Haskell did I/O, approximately:
data Request = PutStrLn String | GetLine | Exit | ...
data Response = Success | Str String | ...
type DialogueIO = [Response] -> [Request]
main :: DialogueIO
main resps1 =
PutStrLn "what's your name?"
: GetLine
: case resps1 of
Success : Str name : resps2 ->
PutStrLn ("hi " ++ name ++ "!")
: Exit
When we write main, we get a lazy list argument and return a lazy list as a
result. The lazy list we return has values like PutStrLn s and GetLine;
after we yield a (request) value, we can examine the next element of the
(response) list, and the RTS will arrange for it to be the response to our
request.
There are ways to make working with this mechanism nicer, but as you can
imagine, the approach gets pretty awkward pretty quickly. Also, it's
error-prone in the same way as the previous one.
Here's another approach which is much less error-prone, and conceptually very
close to how Haskell IO actually behaves:
data ContIO = Exit | PutStrLn String ContIO | GetLine (String -> ContIO) | ...
main :: ContIO
main =
PutStrLn "what's your name?" $
GetLine $ \name ->
PutStrLn ("hi " ++ name ++ "!") $
Exit
The key is that instead of taking a "lazy list" of responses as one big
argument at he beginning of main, we make individual requests that accept one
argument at a time.
Our program is now just a regular data type -- a lot like a linked list, except
you can't just traverse it normally: When the RTS interprets main, sometimes
it encounters a value like GetLine which holds a function; then it has to get
a string from stdin using RTS magic, and pass that string to the function,
before it can continue. Exercise: Write interpret :: ContIO -> IO ().
Note that none of these implementations involve "world-passing".
"world-passing" isn't really how I/O works in Haskell. The actual
implementation of the IO type in GHC involves an internal type called
RealWorld, but that's only an implementation detail.
Actual Haskell IO adds a type parameter so we can write actions that
"produce" arbitrary values -- so it looks more like data IO a = Done a |
PutStr String (IO a) | GetLine (String -> IO a) | .... That gives us more
flexibility, because we can create "IO actions" that produce arbitrary
values.
(As Russell O'Connor points out,
this type is just a free monad. We can write a Monad instance for it easily.)
Where do monads come into it, then? It turns out that we don't need Monad for
I/O, and we don't need Monad for state, so why do we need it at all? The
answer is that we don't. There's nothing magical about the type class Monad.
However, when we work with IO and State (and lists and functions and
Maybe and parsers and continuation-passing style and ...) for long enough, we
eventually figure out that they behave pretty similarly in some ways. We might
write a function that prints every string in a list, and a function that runs
every stateful computation in a list and threads the state through, and they'll
look very similar to each other.
Since we don't like writing a lot of similar-looking code, we want a way to
abstract it; Monad turns out to be a great abstraction, because it lets us
abstract many types that seem very different, but still provide a lot of useful
functionality (including everything in Control.Monad).
Given bindIO :: IO a -> (a -> IO b) -> IO b and returnIO :: a -> IO a, we
could write any IO program in Haskell without ever thinking about monads. But
we'd probably end up replicating a lot of the functions in Control.Monad,
like mapM and forever and when and (>=>).
By implementing the common Monad API, we get to use the exact same code for
working with IO actions as we do with parsers and lists. That's really the only
reason we have the Monad class -- to capture the similarities between
different types.
Another major approach is uniqueness typing, as in Clean. The short story is that handles to state (including the real world) can only be used once, and functions that access mutable state return a new handle. This means that an output of the first call is an input of a second, forcing the sequential evaluation.
Effect typing is used in the Disciple Compiler for Haskell, but to the best of my knowledge it would take considerable compiler work to enable it in, say, GHC. I shall leave discussion of the details to those better-informed than myself.
Well, first what is state? It can manifest as a mutable variable, which you don't have in Haskell. You only have memory references (IORef, MVar, Ptr, etc.) and IO/ST actions to act on them.
However, state itself can be pure as well. To acknowledge that review the 'Stream' type:
data Stream a = Stream a (Stream a)
This is a stream of values. However an alternative way to interpret this type is a changing value:
stepStream :: Stream a -> (a, Stream a)
stepStream (Stream x xs) = (x, xs)
This gets interesting when you allow two streams to communicate. You then get the automaton category Auto:
newtype Auto a b = Auto (a -> (b, Auto a b))
This is really like Stream, except that now at every instant the stream gets some input value of type a. This forms a category, so one instant of a stream can get its value from the same instant of another stream.
Again a different interpretation of this: You have two computations that change over time and you allow them to communicate. So every computation has local state. Here is a type that is isomorphic to Auto:
data LS a b =
forall s.
LS s ((a, s) -> (b, s))
Take a look at A History of Haskell: Being Lazy With Class. It describes two different approaches to doing I/O in Haskell, before monads were invented: continuations and streams.
There is an approach called Functional Reactive Programming that represents time-varying values and/or event streams as a first-class abstraction. A recent example that comes to my mind is Elm (it is written in Haskell and has a syntax similar to Haskell).
I'm curious - what other ways I/O or state can be handled in a pure functional language (both in theory or reality)?
I'll just add to what's already been mentioned here (note: some of these approaches don't seem to have one, so there are a few "improvised names").
Approaches with freely-available descriptions or implementations:
"Orthogonal directives" - see An alternative approach to I/O by Maarten Fokkinga and Jan Kuper.
Pseudodata - see Nondeterminism with Referential Transparency in Functional Programming Languages by F. Warren Burton. The approach is used by Dave Harrison to implement clocks in his thesis
Functional Real-Time Programming: The Language Ruth And Its Semantics, and name supplies in the functional pearl On generating unique names by Lennart Augustsson, Mikael Rittri and Dan Synek; there are also a few library implementations in Hackage.
Witnesses - see Witnessing Side Effects by Tachio Terauchi and Alex Aiken.
Observers - see Assignments for Applicative Languages by Vipin Swarup, Uday S. Reddy and Evan Ireland.
Other approaches - references only:
System tokens:
L. Augustsson. Functional I/O Using System Tokens. PMG Memo 72, Dept Computer Science, Chalmers University of Technology, S-412 96 Göteborg, 1989.
"Effect trees":
Rebelsky S.A. (1992) I/O trees and interactive lazy functional programming. In: Bruynooghe M., Wirsing M. (eds) Programming Language Implementation and Logic Programming. PLILP 1992. Lecture Notes in Computer Science, vol 631. Springer, Berlin, Heidelberg.

Data structure to represent automata

I'm currently trying to come up with a data structure that fits the needs of two automata learning algorithms I'd like to implement in Haskell: RPNI and EDSM.
Intuitively, something close to what zippers are to trees would be perfect: those algorithms are state merging algorithms that maintain some sort of focus (the Blue Fringe) on states and therefore would benefit of some kind of zippers to reach interesting points quickly. But I'm kinda lost because a DFA (Determinist Finite Automaton) is more a graph-like structure than a tree-like structure: transitions can make you go back in the structure, which is not likely to make zippers ok.
So my question is: how would you go about representing a DFA (or at least its transitions) so that you could manipulate it in a fast fashion?
Let me begin with the usual opaque representation of automata in Haskell:
newtype Auto a b = Auto (a -> (b, Auto a b))
This represents a function that takes some input and produces some output along with a new version of itself. For convenience it's a Category as well as an Arrow. It's also a family of applicative functors. Unfortunately this type is opaque. There is no way to analyze the internals of this automaton. However, if you replace the opaque function by a transparent expression type you should get automata that you can analyze and manipulate:
data Expr :: * -> * -> * where
-- Stateless
Id :: Expr a a
-- Combinators
Connect :: Expr a b -> Expr b c -> Expr a c
-- Stateful
Counter :: (Enum b) => b -> Expr a b
This gives you access to the structure of the computation. It is also a Category, but not an arrow. Once it becomes an arrow you have opaque functions somewhere.
Can you just use a graph to get started? I think the fgl package is part of the Haskell Platform.
Otherwise you can try defining your own structure with 'deriving (Data)' and use the "Scrap Your Zipper" library to get the Zipper.
If you don't need any fancy graph algorithms you can represent your DFA as a Map State State. This gives you fast access and manipulation. You also get focus by keeping track of the current state.
Take a look at the regex-tdfa package: http://hackage.haskell.org/package/regex-tdfa
The source is pretty complex, but it's an implementations of regexes with tagged DFAs tuned for performance, so it should illustrate some good practices for representing DFAs efficiently.

Are Rank2Types/RankNTypes practical without polytype variables?

Since type variables cannot hold poly-types, it seems that with Rank*Types we cannot re-use existing functions because of their monotype restriction.
For example, we cannot use the function (.) when the intermediate type is a polytype. We are forced to re-implement (.) at the spot. This is of course trivial for (.) but a problem for more substantial bodies of code.
I also think making ((f . g) x) not equivalent to (f (g x)) a severe blow to referential transparency and its benefits.
It seems to me to be a show-stopper issue, and seems to make the Rank*Types extensions almost impractical for wide-spread use.
Am I missing something? Is there a plan to make Rank*Types interact better with the rest of the type-system?
EDIT: How can you make the types of (runST . forever) work out?
The most recent proposal for Rank-N types is Don's linked FPH paper. In my opinion it's also the nicest of the bunch. The main goal of all these systems is to require as few type annotations as possible. The problem is that when going from Hindley/Milner to System F we lose principal types and type inference becomes undecidable – hence the need for type annotations.
The basic idea of the "boxy types" work is to propagate type annotations as far as possible. The type checker switches between type checking and type inference mode and hopefully no more annotations are required. The downside here is that whether or not a type annotation is required is hard to explain because it depends on implementation details.
Remy's MLF system is so far the nicest proposal; it requires the least amount of type annotations and is stable under many code transformations. The problem is that it extends the type system. The following standard example illustrates this:
choose :: forall a. a -> a -> a
id :: forall b. b -> b
choose id :: forall c. (c -> c) -> (c -> c)
choose id :: (forall c. c -> c) -> (forall c. c -> c)
Both the above types are admissable in System F. The first one is the standard Hindley/Milner type and uses predicative instantiation, the second one uses impredicative instantiation. Neither type is more general than the other, so type inference would have to guess which type the user wants, and that is usually a bad idea.
MLF instead extends System F with bounded quantification. The principal (= most general) type for the above example would be:
choose id :: forall (a < forall b. b -> b). a -> a
You can read this as "choose id has type a to a where a must be an instance of forall b. b -> b".
Interestingly, this alone is no more powerful than standard Hindley/Milner. MLF therefore also allows rigid quantification. The following two types are equivalent:
(forall b. b -> b) -> (forall b. b -> b)
forall (a = forall b. b -> b). a -> a
Rigid quantification is introduced by type annotations and the technical details are indeed quite complicated. The upside is that MLF only needs very few type annotations and there is a simple rule for when they are needed. The downsides are:
Types can become harder to read, because the right hand side of '<' can contain further nested quantifications.
Until recently no explicitly typed variant of MLF existed. This is important for typed compiler transformations (like GHC does). Part 3 of Boris Yakobowski's PhD thesis has a first attempt at such a variant. (Parts 1 & 2 are also interesting; they describe a more intuitive representation of MLF via "Graphical Types".)
Coming back to FPH, its basic idea is to use MLF techniques internally, but to require type annotations on let bindings. If you only want the Hindley/Milner type, then no annotations are necessary. If you want a higher-rank type, you need to specify the requested type, but only at the let (or top-level) binding.
FPH (like MLF) supports impredicative instantiation, so I don't think your issue applies. It should therefore have no issue typing your f . g expression above. However, FPH hasn't been implemented in GHC yet and most likely won't be. The difficulties come from the interaction with equality coercions (and possibly type class constraints). I'm not sure what the latest status is, but I heard that SPJ wants to move away from impredicativity. All that expressive power comes at a cost, and so far no affordable and all-accompanying solution has been found.
Is there a plan to make Rank*Types interact better with the rest of the type-system?
Given how common the ST monad is, at least Rank2 types are common enough to be evidence to the contrary. However, you might look at the "sexy/boxy types" series of papers, for how approaches to making arbitrary rank polymorphism play better with others.
FPH : First-class Polymorphism for Haskell, Dimitrios Vytiniotis, Stephanie Weirich, and Simon Peyton Jones, submitted to ICFP 2008.
See also -XImpredicativeTypes -- which interestingly, is slated for deprecation!
About ImpredicativeTypes: that doesn't actually make a difference (I'm relatively sure) to peaker's question. That extension has to do with datatypes. For instance, GHC will tell you that:
Maybe :: * -> *
(forall a. a -> a) :: *
However, this is sort of a lie. It's true in an impredicative system, and in such a system, you can write:
Maybe (forall a. a -> a) :: *
and it will work fine. That is what ImpredicativeTypes enables. Without the extension, the appropriate way to think about this is:
Maybe :: *m -> *m
(forall a :: *m. a -> a) :: *p
and thus there is a kind mismatch when you try to form the application above.
GHC is fairly inconsistent on the impredicativity front, though. For instance, the type for id I gave above would be:
id :: (forall a :: *m. a -> a)
but GHC will gladly accept the annotation (with RankNTypes enabled, but not ImpredicativeTypes):
id :: (forall a. a -> a) -> (forall a. a -> a)
even though forall a. a -> a is not a monotype. So, it will allow impredicative instantiation of quantified variables that are used only with (->) if you annotate as such. But it won't do it itself, I guess, which leads to the runST $ ... problems. That used to be solved with an ad-hoc instantiation rule (the details of which I was never particularly clear on), but that rule was removed not long after it was added.

Resources