13

Is it possible to write recursive anonymous functions in SML? I know I could just use the fun syntax, but I'm curious.

I have written, as an example of what I want:

val fact =
    fn n => case n of
                 0 => 1
               | x => x * fact (n - 1)
dbmikus
  • 5,018
  • 6
  • 31
  • 37
  • 3
    I'm not an expert on ML, but you are probably looking for something that involves a fixed-point combinator like the Y combinator, which is the typical way that you can build a recursive function out of anonymous functions. – templatetypedef Aug 10 '11 at 17:22
  • @templatetypedef you are correct as long as you only wan't to work with anonymous functions (keeping in mind that the original question doesn't use anonymous functions), however this is not a pretty way of doing it. See the last part of my answer for an example :) – Jesper.Reenberg Aug 11 '11 at 11:28

4 Answers4

17

The anonymous function aren't really anonymous anymore when you bind it to a variable. And since val rec is just the derived form of fun with no difference other than appearance, you could just as well have written it using the fun syntax. Also you can do pattern matching in fn expressions as well as in case, as cases are derived from fn.

So in all its simpleness you could have written your function as

val rec fact = fn 0 => 1
                | x => x * fact (x - 1)

but this is the exact same as the below more readable (in my oppinion)

fun fact 0 = 1
  | fact x = x * fact (x - 1)

As far as I think, there is only one reason to use write your code using the long val rec, and that is because you can easier annotate your code with comments and forced types. For examples if you have seen Haskell code before and like the way they type annotate their functions, you could write it something like this

val rec fact : int -> int =
fn 0 => 1
 | x => x * fact (x - 1)

As templatetypedef mentioned, it is possible to do it using a fixed-point combinator. Such a combinator might look like

fun Y f =
    let
      exception BlackHole
      val r = ref (fn _ => raise BlackHole)
      fun a x = !r x
      fun ta f = (r := f ; f)
    in
      ta (f a)
    end

And you could then calculate fact 5 with the below code, which uses anonymous functions to express the faculty function and then binds the result of the computation to res.

val res =
    Y (fn fact =>
       fn 0 => 1
        | n => n * fact (n - 1)
      )
      5                       

The fixed-point code and example computation are courtesy of Morten Brøns-Pedersen.


Updated response to George Kangas' answer:

In languages I know, a recursive function will always get bound to a name. The convenient and conventional way is provided by keywords like "define", or "let", or "letrec",...

Trivially true by definition. If the function (recursive or not) wasn't bound to a name it would be anonymous.

The unconventional, more anonymous looking, way is by lambda binding.

I don't see what unconventional there is about anonymous functions, they are used all the time in SML, infact in any functional language. Its even starting to show up in more and more imperative languages as well.

Jesper Reenberg's answer shows lambda binding; the "anonymous" function gets bound to the names "f" and "fact" by lambdas (called "fn" in SML).

The anonymous function is in fact anonymous (not "anonymous" -- no quotes), and yes of course it will get bound in the scope of what ever function it is passed onto as an argument. In any other cases the language would be totally useless. The exact same thing happens when calling map (fn x => x) [.....], in this case the anonymous identity function, is still in fact anonymous.

The "normal" definition of an anonymous function (at least according to wikipedia), saying that it must not be bound to an identifier, is a bit weak and ought to include the implicit statement "in the current environment".

This is in fact true for my example, as seen by running it in mlton with the -show-basis argument on an file containing only fun Y ... and the val res ..

val Y: (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b
val res: int32

From this it is seen that none of the anonymous functions are bound in the environment.

A shorter "lambdanonymous" alternative, which requires OCaml launched by "ocaml -rectypes":

(fun f n -> f f n) 
(fun f n -> if n = 0 then 1 else n * (f f (n - 1))
7;; Which produces 7! = 5040.

It seems that you have completely misunderstood the idea of the original question:

Is it possible to write recursive anonymous functions in SML?

And the simple answer is yes. The complex answer is (among others?) an example of this done using a fix point combinator, not a "lambdanonymous" (what ever that is supposed to mean) example done in another language using features not even remotely possible in SML.

Jesper.Reenberg
  • 5,944
  • 23
  • 31
  • “[…] since val rec is just the derived form of fun […]”: isn't it the opposite? – Hibou57 Jul 23 '14 at 00:20
  • 1
    No. Well perhaps we mean the same thing, but look at it from two different angles. `val rec` is part of the core language, and the `fun` keyword is the derived form. I don't have my definition at hand, but see section 3.4 of [http://homepages.inf.ed.ac.uk/stg/NOTES/notes.pdf ] (it was the best I could find on google). – Jesper.Reenberg Jul 29 '14 at 11:13
9

All you have to do is put rec after val, as in

val rec fact =
        fn n => case n of
                     0 => 1
                   | x => x * fact (n - 1)

Wikipedia describes this near the top of the first section.

murgatroid99
  • 19,007
  • 10
  • 60
  • 95
3
let fun fact 0 = 1
      | fact x = x * fact (x - 1)
in
  fact
end

This is a recursive anonymous function. The name 'fact' is only used internally.

Some languages (such as Coq) use 'fix' as the primitive for recursive functions, while some languages (such as SML) use recursive-let as the primitive. These two primitives can encode each other:

fix f => e   
  := let rec f = e in f end

let rec f = e ... in ... end 
  := let f = fix f => e ... in ... end 
Peng Wang
  • 93
  • 4
-1

In languages I know, a recursive function will always get bound to a name. The convenient and conventional way is provided by keywords like "define", or "let", or "letrec",...

The unconventional, more anonymous looking, way is by lambda binding. Jesper Reenberg's answer shows lambda binding; the "anonymous" function gets bound to the names "f" and "fact" by lambdas (called "fn" in SML).

A shorter "lambdanonymous" alternative, which requires OCaml launched by "ocaml -rectypes":

(fun f n -> f f n)
(fun f n -> if n = 0 then 1 else n * (f f (n - 1))
7;;

Which produces 7! = 5040.

  • 2
    Did you even read the code? Answering with an OCaml example doesn't bring value to the original question especially when using recursive types which SML doesn't have. All in all I don't see the point of your post other than to state some already know facts. See my updated post. – Jesper.Reenberg Oct 13 '11 at 12:18