Is the fun keyword strictly necessary in the language grammar?

I write anonymous functions in nearly every program I write. I am curious if the fun keyword is a historic artifact or actually an essential token for disambiguation in the grammar. That is, I know it’s required now for anon fns, but I’d prefer to write: x -> x *. 2 vs fun x -> x *. 2. Perhaps there’s a preprocessor available to autofill fun in? I see https://askra.de/software/ocaml-doc/4.02/full-grammar.html. I also observe that -> is used in various other expressions, but unsure what would fall apart if fun was dropped.

1 Like

You can use either one for a single-argument function, but in the case of a function with several arguments, I do not think the following syntax is accepted:

function x y z -> (* ... *) (* invalid? *)

whereas the fun keyword lets you match as many arguments as you need:

fun x y z -> (* ... *) (* perfectly valid *)

However, if your question concerns the need of such a syntactic construct, then yes, you are right, most of the syntax in OCaml is syntactic sugar and can be replaced with something more “primitive”. I guess something like the following is correct (thanks to curryfication rules):

function x -> function y -> function z -> (* ... *)

If we push this way of reasoning to its full extent, we get an OCaml flavour of lambda-calculus, but the resulting programming language is probably not as practical. I hope my answer is what you were looking for.

It’s essential for disambiguation. Without it, you wouldn’t know whether to parse the first x as a pattern or an expression without looking ahead to see whether there is an arrow or not. While some languages do have complicated parsers that can handle this, or even typecheck while they parse so that they know whether to expect a function or not, in OCaml you would have to make huge changes to the parser to support this.

5 Likes

Slightly unrelated, but on a similar note, I often use a small ppx implementing anaphoric lambdas for this purpose.

So instead of:

fun x -> x + 1

I just use:

[%a it + 1 ] 

Maybe not ideal for production code, but it certainly makes certain patterns in my hobby projects a lot more concise.

@Gopiandcode, have a URL to such a ppx?

I often use (( + ) 1) or (( *. ) 2.). Because partial application works with operators as well as functions, you often just don’t need the full-fledged function literal syntax. Fortunate contrast with, e.g., Standard ML, where operator parameters are tupled.

Agreed. I try and partial as much as possible to avoid formally opening a function, but often have arg ordering issues. E.g.

List.map ~f:(fun s -> String.get s 0)

Perhaps if there’s a mechanism to partial on of out order args? e.g. (String.get _ 0), s.t. the passed arg fills the first placeholder? I seem to recall seeing this in some language.

It exists with the reason syntax but not the ocaml one. There was a discussion about this on github but I can’t find it :frowning: Some libraries are providing a flip function which can help.

I haven’t published it because it was so small, but all you need is the following:

open Ppxlib

let name = "a"

let expand ~loc ~path:_ expr =
  match expr with
  | expr ->
    [%expr fun it -> [%e expr]]

let ext =
  Extension.declare name Extension.Context.expression
    Ast_pattern.(single_expr_payload __)
    expand

let () = Driver.register_transformation name ~extensions:[ext]
3 Likes

Huh, https://reasonml.chat/t/partial-application-and/714. So _ partial placeholders may feasibly work in plain OCaml? @yawaramin, you piped in that prior thread–any insight here?

edit: i misread “It exists with the reason syntax but not the ocaml one”

Dang. Ya, that would be a great feature! I’d use it often.

I agree that in this case partial application would work better, but the ppx is quite useful when creating pipe chains of multi-argument functions - i.e something like

let _ =  x
    |> update
    |> [%a store it 3]
    |> [%a present it Graphics.display]
2 Likes

Actually, I think it is not that difficult: all you have to do is have the same parsing rule for expressions and patterns. In other words, merge the two together (possibly also merge the AST) and disambiguate as a second step. This is possible because most patterns (except as, exception and maybe a few others?) use basically the same syntax as expressions.

Maybe there are some corner-cases in OCaml where it just does not work, but I implemented a couple languages where I did exactly that.

Yes it is necessary. Also, we want to keep the fun going. :grinning:

4 Likes

Right, I was just going to say, it would be no fun without it.

1 Like

Are you confident that it’s not too funky that we have duplicate function syntax?

1 Like
List,map ~f:(inv2 String.get 0)

with inv2 f y x = f x y ?

Fun.flip does exactly that and is now in the Stdlib