16

I'm currently learning OCaml today I came up to this piece of code.

let rec tree_to_list acc = function
  | Leaf x -> x::acc
  | Node (t1,t2) -> tree_to_list (tree_to_list acc t2) t1

As far as I understand this function does the same than this one

let rec tree_to_list2 acc t = match t with
  | Leaf x -> x::acc
  | Node (t1, t2) -> tree_to_list t1 (tree_to_list2 acc t2)

However, I do not understand the syntax behind the first function. I find the keyword function confusing. It is supposed to take one argument only such as :

function x -> x + 2

Could someone please help me understand the syntax of the first function and if any the difference in terms of how both functions are evaluated. Thanks in advance.

Colin G.D.
  • 351
  • 1
  • 3
  • 9
  • Yes, a little confusing, we have 3 function definition syntaxes, and pattern matching on the parameter binding side - yes, you can pattern match left of the equal sign. – Str. Oct 21 '15 at 19:27
  • Colin G.D. There's a mooc in english Introduction to Functional Programming in OCaml (www.france-universite-numerique-mooc.fr). It's still open. He began this week (with an introduction by Xavier Leroy). – V. Michel Oct 21 '15 at 22:44
  • Hi @V.Michel I know about this mooc my teachers are the ones behind it, but thank you anyway. – Colin G.D. Oct 22 '15 at 06:36

4 Answers4

17

Functions in OCaml are defined by giving patterns for the arguments. The common case of a simple variable name (like acc in your first function) is just a particular kind of pattern that matches all values.

So, one way to look at it is that fun defines a function with any number of arguments that can each be given by one pattern. On the other hand, function defines a function with one argument that can be given by any number of patterns.

# let dot = fun (a, b) (c, d) -> a *. c +. b *. d
val dot : float * float -> float * float -> float = <fun>

# let geti = function None -> 0 | Some i -> i;;
val geti : int option -> int = <fun>

The fun form can, in essence, be absorbed into the left hand side of a let to give a more concise notation.

That is,

let f = fun p1 p2 -> ...

can be written as

let f p1 p2 = ...

So for example:

let dot (a, b) (c, d) = a *. c +. b *. d

Your first function is using a combination of the two (a concise fun and a function on the right).

Jeffrey Scofield
  • 65,646
  • 2
  • 72
  • 108
11

As far as I understand this function does the same than this one

You are correct in that the two code snippets are evaluated the same.

Could someone please help me understand the syntax of the first function

As @JeffreyScofield seems to have answered this part very nicely, I'll focus on the second part.

if any the difference in terms of how both functions are evaluated

The tl;dr is there is no difference and the assembly produced is actually identical. We'll use a simple Fibonacci example to show the assembly emitted both using the match with and function notations.

let rec fib n = match n with
| 0 -> 0
| 1 -> 1
| i -> fib (i - 1) + fib (i - 2)

and

let rec fib = function
| 0 -> 0
| 1 -> 1
| i -> fib (i - 1) + fib (i - 2)

both produce

fib:
    subq $24, %rsp
.L102:
    cmpq $1, %rax
    je .L100
    cmpq $3, %rax
    je .L101
    movq %rax, 0(%rsp)
    addq $-4, %rax
    call fib
.L103:
    movq %rax, 8(%rsp)
    movq 0(%rsp), %rax
    addq $-2, %rax
    call fib
.L104:
    movq 8(%rsp), %rbx
    addq %rbx, %rax
    decq %rax
    addq $24, %rsp
    ret
.L101:
    movq $3, %rax
    addq $24, %rsp
    ret
.L100:
    movq $1, %rax
    addq $24, %rsp
    ret

Note: I intentionally removed the .aligns and such.

To verify the claim that these produce the same assembly (and are thus evaluated the same), you can simply put each function in a file and then run

$ ocamlopt -S fib-with-match.ml
$ ocamlopt -S fib-with-function.ml

when you diff the two, you should see it return with no difference:

$ diff fib-with-match.s fib-with-function.s
$

It's very common to have functions that only contain match expressions in OCaml, so as @JeffreyScofield said, function has an argument that can be used for pattern matching. Therefore, it's effectively syntactic sugar.

Source:

Martin Jambon
  • 4,629
  • 2
  • 22
  • 28
Michael Recachinas
  • 2,739
  • 2
  • 20
  • 29
2

My way to explain the function definition in OCaml:

These are equivalent:

let name p1 p2 ... pn = expr
let name = function p1 -> function p2 -> ... -> function pn -> expr
let name = fun p1 p2 ... pn -> expr

How to memorize it:

  • the first is syntactic sugar,

  • the second is what it really does internally,

  • the third is legacy from caml.

Now function takes only one argument, but it is often used like this - these are equivalent, you are matching on p3:

let f1 p1 p2 p3 = match p3 with
 | []  -> expr
 | ...

let f2 p1 p2 = function
  | []  -> expr
  | ...

You see the second version saves some source characters, removing visual clutter. Or more: there is no need to bind a value to p3 without using the p3 variable, because pattern matching is the best binding construct.

Str.
  • 1,389
  • 9
  • 14
1

The first function is just not naming explicitly its argument. You can do the same with the function that adds 2 :

let f = (+) 2;;

That will add 2 to any number and the arg is not explicitly named.

Pierre G.
  • 4,346
  • 1
  • 12
  • 25