Bad use of optional arguments

Good evening,

At this page « https://ocaml.org/problems#5 », the exercice asks to write the « rev » function, which reverses a list :

let rev list =
  let rec aux acc = function
    | [] -> acc
    | h :: t -> aux (h :: acc) t
  in aux [] list;;

Currently, I read this book « Real Worl Ocam: Functionnal Programming for the Masses » and I tried to use « optional argument ». So I decided to write the « rev » function like this :

let rec rev list ?(acc=[]) =
  match list with
  | [] -> acc
  | h :: t -> rev t ~acc:(h :: acc);;

The compiler doesn’t accept this solution and writes : « Warning : this optional argument cannot be erased ».

Could someone explain why ?

1 Like

Yes! It’s down to syntax and currying.

If the optional parameter is last, the compiler can’t tell, when you call the function and you only pass in one argument, if you intend for that function to have the default argument passed in or to be a curried version of the function, i.e. return a new function that expects the missing arguments.

There’s an easy fix - always put optional parameters before required ones. If ever you only have optional parameters, you can put a dummy unit () at the end to force it to work.

Also, for what it’s worth, I think the first implementation without the optional parameter is better - otherwise you are leaking an inner implementation detail on the function signature.

4 Likes

Thank you! You’re right! This code works :

let rec rev ?(acc=[]) list =
  match list with
  | [] -> acc
  | h :: t -> rev t ~acc:(h :: acc);;

The section « Optional Arguments and Partial Application » of the book, explains what you wrote : « The rule is: an optional argument is erased as soon as the first positional (i.e., neither labeled nor optional) argument defined after the optional argument is passed in. »