1

I executed the following command in utop with Jane street Base library installed

open Base;;
List.fold;;

It prints

- : 'a list -> init:'accum -> f:('accum -> 'a -> 'accum) -> 'accum = <fun>

I interpret this as the fold function first parameter is a list of values. second is the initial value and 3rd is the fold function. The folder function whose first parameter is the accumulator and second parameter is the item from the list being folded.

With this interpretation I write this code

List.fold [Some 1; None; None; Some 2] 0 (fun accm x -> match x with | None -> accum | Some x -> accum + x)

This doesn't work and it prints something weird on the screen

- : init:(int -> (int -> int option -> int) -> '_weak2) ->
    f:((int -> (int -> int option -> int) -> '_weak2) ->
       int option -> int -> (int -> int option -> int) -> '_weak2) ->
    '_weak2
= <fun>

Now If I change my code in utop to use named parameters

List.fold [Some 1; None; Some 2] ~init:0 ~f:(fun accum x -> match x with | None -> accum | Some x -> accum + x);;

Now it works. What's going on? I passed the parameters in the same order as the documented signature suggested? then why am I being forced to use named parameters?

Knows Not Much
  • 30,395
  • 60
  • 197
  • 373
  • There's no function named `List.fold` in the OCaml standard library. So you're using some additional libraries no doubt. It's probably not too critical for this question but in general it's best to describe your environment carefully. – Jeffrey Scofield Nov 02 '22 at 22:05
  • 1
    fixed. I have installed Base library. I am reading the book https://dev.realworldocaml.org and as part of setup installed Base. – Knows Not Much Nov 02 '22 at 22:19
  • OK I think I should delete the question. I changed my .ocamlinit file and removed `open Base` and now it works as expected. I think that library is doing something funny. Not sure what its doing though. what is all that "weak" stuff. – Knows Not Much Nov 02 '22 at 22:23
  • There is something specific going on, but I don't have Base here so I can't reproduce your results. If nobody steps up with an explanation I'll look into installing Base. At any rate weak type variables aren't too strange, they have a specific meaning. – Jeffrey Scofield Nov 02 '22 at 22:24
  • The error message is weird I think mostly because `fold` can return anything, even a function, and since it's not constrained by `~init` or `~f` it will be inferred to be a function that takes the extra arguments you've given it and returns something unknown. – glennsl Nov 02 '22 at 22:30

2 Answers2

3

Argument labels can only be omitted in non-ambiguous full applications.

In particular, this is never the case for labelled functions with a polymorphic return type like fold. Indeed, for such function, there is no clear notion of full application.

For instance, if you look at your initial application:

List.fold [Some 1; None; None; Some 2] 0
  (fun accm x -> match x with | None -> accum | Some x -> accum + x)

it could be completed into the following full application:

List.fold 
  [Some 1; None; None; Some 2] 0
  (fun acc x -> match x with None -> acc | Some x -> acc + x)
  ~init:(fun x f -> f x None)
  ~f:(fun f _ -> f )

Consequently, your initial code

List.fold [Some 1; None; None; Some 2] 0
  (fun accm x -> match x with | None -> accum | Some x -> accum + x)

is not a full application, but a valid partial application where the labelled arguments are still missing.

octachron
  • 17,178
  • 2
  • 16
  • 23
2

I'm going to guess you're using the Jana Street base library. So let's start with a link to those docs..

The List.fold in that library does accept the init value and the function to run as named parameters. You have not provided those named parameters in:

List.fold [Some 1; None; None; Some 2] 0 (fun accm x -> match x with | None -> accum | Some x -> accum + x)

If you try partially applying:

List.fold [Some 1; None; None; Some 2]

You will see:

- : init:'_weak2 -> f:('_weak2 -> int option -> '_weak2) -> '_weak2 = <fun>

This is a new function with lots of weak polymorphic types. Jeffrey in particular has written extensively on this subject on Stack Overflow. One example: https://stackoverflow.com/a/25798225/15261315.

You're then applying it to the value 0, which yields:

- : init:(int -> '_weak3) ->
    f:((int -> '_weak3) -> int option -> int -> '_weak3) -> '_weak3

We can see this with a simple function of our own devising:

utop # let f a ~b ~g = g a b;;
val f : 'a -> b:'b -> g:('a -> 'b -> 'c) -> 'c = <fun>

utop # f 5;;
- : b:'_weak4 -> g:(int -> '_weak4 -> '_weak5) -> '_weak5 = <fun>

utop # f 5 6;;
- : b:'_weak6 -> g:(int -> '_weak6 -> int -> '_weak7) -> '_weak7 = <fun>
Chris
  • 26,361
  • 5
  • 21
  • 42