[MLton] Fixed points in SML

Wesley W. Terpstra wesley at terpstra.ca
Tue Aug 29 16:49:40 PDT 2006


I was reading http://en.wikipedia.org/wiki/Lambda_calculus and found  
their fixed-points interesting. Being able to do away with recursive  
definitions sounded interesting. I then tried to implement them in  
SML and had an adventure.

Let's start with the fixed point definition they gave:
Y = λ g. (λ x. g (x x)) (λ x. g (x x))
To save typing, I've changed this to:
Y = λ g. (λ x. (x x)) (λ x. g (x x))
... the savings will be more later.

A first blush at writing this in SML:
val Y = fn g => (fn x => x x) (fn x => g (x x))
... however, this fails to type-check because the type signature of  
the last lambda expression is:
(((((... ) -> 'a) -> 'a) -> 'a
which is impossible to write in SML.

So, I tried the following elaboration:
local
   datatype 'a t = T of 'a t -> 'a
in
   val Y : ('a -> 'a) -> 'a = fn g => (fn x => x (T x)) (fn (T x) =>  
g (x (T x)))
end
The idea here was that 'a t = ((((... ) -> 'a) -> 'a) -> 'a. Now the  
last lambda expression is possible.

However, this went into an infinite loop because SML is eager, and  
will expand the recursion out to infinity.

My next step was a simple iota expansion on the last lambda  
expression to defer evaluation:
local
   datatype 'a t = T of 'a t -> 'a
in
   val Y : (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b = fn g => (fn x => x  
(T x)) (fn (T x) => fn y => g (x (T x)) y)
end
Then it worked!

val nonrecursive_factorial = fn f => fn x => if x = 0 then 1 else x *  
f (x - 1)
val factorial = Y nonrecursive_factorial

The point of my email is this: I believe both changes must be made to  
ANY fixed point algorithm implemented in SML. It seems to me that a  
datatype is necessary to implement recursion, and I challenge anyone  
to find a SML fixed-point implementation that doesn't use a datatype.  
It also seems to me that the iota expansion is necessary and that a  
fixed point function in SML must have type signature (('a -> 'b) ->  
'a -> 'b) -> 'a -> 'b. That is, a function with signature ('a -> 'a) - 
 > 'a can never terminate, even if 'a is a function like  
nonrecursive_factorial. Am I right? Anyone have a counter-example?




More information about the MLton mailing list