OCaml partial application syntax enhancement
In many situations in functional programming it's handy to be able to produce "specialized" functions by fixing the values of part of the arguments of a more generic one. This is usually referred to as partial application. Here's a simple example in OCaml:
# (+) 1 ;;
- : int -> int = <fun>
# let f = (+) 1 ;;
val f : int -> int = <fun>
# f 2 ;;
- : int = 3
Partial application allows writing more elegant code in some cases:
# List.map ((+) 1) [0; 1; 2; 3; 4] ;;
- : int list = [1; 2; 3; 4; 5]
# let f c a b = c * (a + b) ;;
val f : int -> int -> int -> int = <fun>
# List.map2 (f 2) [0; 1; 2] [1; 2; 3] ;;
- : int list = [2; 6; 10]
List.map (fun x -> 1 + x) [0; 1; 2; 3; 4] ;;
List.map2 (fun x y -> f 2 x y) [0; 1; 2] [1; 2; 3]
But the support for partial application is somewhat limited - there's no syntax in OCaml for fixing an arbitrary subset of arguments, only a number of leftmost arguments (upd: I mean positional arguments here, no keyword arguments). This limitation disallows writing such elegant code for example in following case: we want to substract 5 from all elements of a list (i.e. we want to fix the second argument). The code has to look like this:
# List.map (fun x -> (-) x 5) [1; 2; 3; 4; 5] ;;
- : int list = [-4; -3; -2; -1; 0]
To overturn this limitation the pa_papply syntax extension have been created:
open Camlp4
module Id : Sig.Id = struct
let name = "Partial apply syntax extension"
let version = "0.0.1"
end
module Make (Syn : Sig.Camlp4Syntax) = struct
open Sig
include Syntax
EXTEND Gram
expr: LEVEL "apply" (* LEFTA *)
[ [ e = expr; stubs = LIST1 "_" ->
let il =
let rec enum i = function [] -> [] | _ :: t -> i :: enum (i + 1) t
in enum 0 stubs
in
let xl = List.map (fun i -> "__papply_x_" ^ string_of_int i) il in
let eapplyx =
List.fold_left (fun accu xi -> <:expr< $accu$ $lid:xi$ >>) e xl in
let funx =
List.fold_right
(fun xi rest -> <:expr< fun $lid:xi$ -> $rest$>>)
xl <:expr< $eapplyx$ __papply_z>>
in <:expr< fun __papply_z -> $funx$ >> ] ] ;
END
end
module M = Register.OCamlSyntaxExtension (Id) (Make)
This extension is compiled by running following command:
# ocamlc -I +camlp4 -pp camlp4orf -c pa_papply.ml
And the command:
# ocamlc -pp "camlp4o -I . pa_papply.cmo" -c test.ml
compiles for instance file test.ml written in our extended syntax.
pa_papply enables to rewrite the previous example in the following way:
# List.map ((-) _ 5) [1; 2; 3; 4; 5] ;;
- : int list = [-4; -3; -2; -1; 0]
# let f x y z = (x + y) * z ;;
val f : int -> int -> int -> int = <fun>
# f 1 2 3 ;;
- : int = 9
# f _ 2 1 3 ;;
- : int = 9
# f 1 _ 3 2 ;;
- : int = 9
# f _ _ 3 1 2 ;;
- : int = 9
Comments, suggestions and bug reports are welcome.







