Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OCaml, F# successive, cascading let bindings

Tags:

f#

ocaml

It is typical in OCaml or F# to have successive let bindings in the form:

let a1 = ...
let a2 = ...
let a3 = ...
let f1 = ...
let f2 = ...
let f3 = ... 
f3 a1 a2 a3

In many cases some of these let bindings (e.g. f1 and f2 in the example above) are only used as building blocks of the expression or function immediately following them and not referenced again afterwards. In other cases some values are indeed used at the end of the "chain" (e.g. a1, a2 and a3 in the example above). Is there any syntactic idiom to make these differences in scope explicit?

like image 702
Marcus Junius Brutus Avatar asked Aug 08 '12 21:08

Marcus Junius Brutus


People also ask

What are functions in OCaml?

Function in ocaml is a expression. That means, a function is a value that represents the function. This is also called anonymous function, lambda. (* syntax for a function expression *) fun n -> n + 1;; (* applying a function to a value *) (fun n -> n + 1) 2;; (* ⇒ 3 *)

What does -> mean in OCaml?

The way -> is defined, a function always takes one argument and returns only one element. A function with multiple parameters can be translated into a sequence of unary functions.

What does tilde mean in OCaml?

The tilde introduces the feature known as labelled argument. OCaml standard library has module List where functions are declared without labelled arguments and module ListLabels which uses them.


2 Answers

On can use this to make clear that temp is used only in the definition of a1:

let a1 =
  let temp = 42 in
  temp + 2 in
let a2 = ...

The scope of temp is indeed restricted to the definition of a1.

Another template is reusing the same name to hide its previous use, thus also making it clear that the previous use is temporary:

let result = input_string inchan in
let result = parse result in
let result = eval result in
result

Reusing the same name is debatable, though.

Of course one always has comments and empty lines:

let a1 = ...
let a2 = ...
let a3 = ...

(*We now define f3:*)
let f1 = ...
let f2 = ...
let f3 = ...

f3 a1 a2 a3

Edit: as pointed out by fmr, I'm also fond of the pipe operator. It's not defined by default in OCaml, use

let (|>) x f = f x;;

Then you can write something like

input_string inchan |> parse |> eval |> print
like image 72
jrouquie Avatar answered Oct 07 '22 13:10

jrouquie


In addition to jrouquie's answer, you can avoid giving names to intermediate values by judicious use of function composition and other combinators. I especially like the following three provided by Batteries:

# let ( |> ) x f = f x;;
val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun>
# let ( |- ) f g x = g (f x);;
val ( |- ) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c = <fun>
# let flip f x y = f y x;;
val flip : ('a -> 'b -> 'c) -> 'b -> 'a -> 'c = <fun>

A small example using |> is

# [1;2;3]
  |> List.map string_of_int
  |> String.concat "; "
  |> Printf.sprintf "[%s]";;
- : string = "[1; 2; 3]"

You'll end up needing |- and flip in more realistic examples. This is known as point-free or tacit programming.

like image 40
Ashish Agarwal Avatar answered Oct 07 '22 12:10

Ashish Agarwal