\section{s:binding-operators}{Binding operators} %HEVEA\cutname{bindingops.html} (Introduced in 4.08.0) \begin{syntax} let-operator: | 'let' (core-operator-char || '<') { dot-operator-char } ; and-operator: | 'and' (core-operator-char || '<') { dot-operator-char } ; operator-name : ... | let-operator | and-operator ; letop-binding : pattern '=' expr | value-name ; expr: ... | let-operator letop-binding { and-operator letop-binding } in expr ; \end{syntax} Binding operators offer syntactic sugar to expose library functions under (a variant of) the familiar syntax of standard keywords. Currently supported ``binding operators'' are "let" and "and", where "" is an operator symbol, for example "and+$". Binding operators were introduced to offer convenient syntax for working with monads and applicative functors; for those, we propose conventions using operators "*" and "+" respectively. They may be used for other purposes, but one should keep in mind that each new unfamiliar notation introduced makes programs harder to understand for non-experts. We expect that new conventions will be developed over time on other families of operator. \subsection{ss:letop-examples}{Examples} Users can define {\em let operators}: \begin{caml_example}{verbatim} let ( let* ) o f = match o with | None -> None | Some x -> f x let return x = Some x \end{caml_example} and then apply them using this convenient syntax: \begin{caml_example}{verbatim} let find_and_sum tbl k1 k2 = let* x1 = Hashtbl.find_opt tbl k1 in let* x2 = Hashtbl.find_opt tbl k2 in return (x1 + x2) \end{caml_example} which is equivalent to this expanded form: \begin{caml_example}{verbatim} let find_and_sum tbl k1 k2 = ( let* ) (Hashtbl.find_opt tbl k1) (fun x1 -> ( let* ) (Hashtbl.find_opt tbl k2) (fun x2 -> return (x1 + x2))) \end{caml_example} Users can also define {\em and operators}: \begin{caml_example}{verbatim} module ZipSeq = struct type 'a t = 'a Seq.t open Seq let rec return x = fun () -> Cons(x, return x) let rec prod a b = fun () -> match a (), b () with | Nil, _ | _, Nil -> Nil | Cons(x, a), Cons(y, b) -> Cons((x, y), prod a b) let ( let+ ) f s = map s f let ( and+ ) a b = prod a b end \end{caml_example} to support the syntax: \begin{caml_example}{verbatim} open ZipSeq let sum3 z1 z2 z3 = let+ x1 = z1 and+ x2 = z2 and+ x3 = z3 in x1 + x2 + x3 \end{caml_example} which is equivalent to this expanded form: \begin{caml_example}{verbatim} open ZipSeq let sum3 z1 z2 z3 = ( let+ ) (( and+ ) (( and+ ) z1 z2) z3) (fun ((x1, x2), x3) -> x1 + x2 + x3) \end{caml_example} \subsection{ss:letops-conventions}{Conventions} An applicative functor should provide a module implementing the following interface: \begin{caml_example*}{verbatim} module type Applicative_syntax = sig type 'a t val ( let+ ) : 'a t -> ('a -> 'b) -> 'b t val ( and+ ): 'a t -> 'b t -> ('a * 'b) t end \end{caml_example*} where "(let+)" is bound to the "map" operation and "(and+)" is bound to the monoidal product operation. A monad should provide a module implementing the following interface: \begin{caml_example*}{verbatim} module type Monad_syntax = sig include Applicative_syntax val ( let* ) : 'a t -> ('a -> 'b t) -> 'b t val ( and* ): 'a t -> 'b t -> ('a * 'b) t end \end{caml_example*} where "(let*)" is bound to the "bind" operation, and "(and*)" is also bound to the monoidal product operation. \subsection{ss:letop-rules}{General desugaring rules} The form \begin{verbatim} let x1 = e1 and x2 = e2 and x3 = e3 in e \end{verbatim} desugars into \begin{verbatim} ( let ) (( and ) (( and ) e1 e2) e3) (fun ((x1, x2), x3) -> e) \end{verbatim} This of course works for any number of nested "and"-operators. One can express the general rule by repeating the following simplification steps: \begin{itemize} \item The first "and"-operator in \begin{center} "let x1 = e1 and x2 = e2 and... in e" \end{center} can be desugared into a function application \begin{center} "let (x1, x2) = ( and ) e1 e2 and... in e". \end{center} \item Once all "and"-operators have been simplified away, the "let"-operator in \begin{center} "let x1 = e1 in e" \end{center} can be desugared into an application \begin{center} "( let ) e1 (fun x1 -> e)". \end{center} \end{itemize} Note that the grammar allows mixing different operator symbols in the same binding ("", "", "" may be distinct), but we strongly recommend APIs where let-operators and and-operators working together use the same symbol. \subsection{ss:letops-punning}{Short notation for variable bindings (let-punning)} (Introduced in 4.13.0) When the expression being bound is a variable, it can be convenient to use the shorthand notation "let+ x in ...", which expands to "let+ x = x in ...". This notation, also known as let-punning, allows the "sum3" function above can be written more concisely as: \begin{caml_example}{verbatim} open ZipSeq let sum3 z1 z2 z3 = let+ z1 and+ z2 and+ z3 in z1 + z2 + z3 \end{caml_example} This notation is also supported for extension nodes, expanding "let%foo x in ..." to "let%foo x = x in ...". However, to avoid confusion, this notation is not supported for plain "let" bindings.