The Ocaml and Haskell languages are descended from the ISWIM language, described in the famous article by Peter Lendin "The next 700 programming languages". In it, the author, starting from the LISP language, creates a new programming language and, in particular, introduces keywords let
, and
and where
, which are widely used in the languages of the ML family. Sooner or later, any inquisitive mind, engaged in functional programming, has a question: why didn't the keyword where
widely used in Haskell take root in Ocaml ?
From my point of view, this is mainly due to the differences in the semantics of these languages, namely the imperative-energetic nature of Ocaml and the purity-laziness of evaluation in Haskell (which are directly and strongly related to the impure / pure nature of these languages).
Both of these expressions, let
and where
, are derived from (let ...)
the LISP language, which has two variants of this special form: (let ...)
and (let* ...)
. The variant (let* ...)
differs in that all bindings in the block occur sequentially and can depend on each other:
(let* ((x 3)
(y (+ x 2))
(z (+ x y 5)))
(* x z))
In some dialects of Scheme, variable declarations can be automatically reordered by the interpreter, so it becomes unnecessary to write them in the "correct" order. Both options for binding, let ... in
and where
correspond to this "advanced" option (let* ...)
. However, in Ocaml, a keyword is used to separate "parallel bindings" and
, while in Haskell they are simply placed in one block.
If you look exclusively at the essence of things, you can see that the expressions let ... in
and where
differ in two aspects: the place where the binding is placed, and the number of expressions in the block.
Binding names before and after use.
- let ... in
, , where
:
let x = 1 in
x + 1
z = x + 1
where x = 1
, let ... in Ocaml, , , / . ,
let x = Printf.printf "Hello ";
"World!"
in
Printf.printf "%s" x
. top-level Ocaml, , open
let () = ...
, where non-strict Haskell, term/graph reduction. , where
, :
main = putStrLn (x ++ y)
where x = "Hello "
y = "World!"
z = undefined
: x
y
, . z
, - .
x
, y
, z
let ... in
, Haskell, - z
, . , do
, let
.
shadowing
C let ... in
, Ocaml, Haskell, . where
- :
let x = 1 in
let y = 1 in
x + y
z = x + y
where x = 1
y = 1
, , , , , , "shadowing". Ocaml shadowing , :
let x = 1 in
let x = x * 10 in
x * x
, , :
x := 1;
x := x * 10;
return x*x;
Haskell, where
, "", shadowing , . shadowing , top-level , - non-strict . , Haskell
x = x + 1
.
shadowing Ocaml Haskell , Ocaml , Ocaml Haskell (backpack , - t
M
Ocaml ).
Ocaml , -, (.mli) (.ml). , , -, , top-level , . - , Ocaml top-level , . , let ... in (., report_constructor_mismatch https://github.com/ocaml/ocaml/blob/trunk/typing/includecore.ml#L212 )
Haskell , . , , - , , top-level . , where shadowing.
, , - Clean.
, , where
, let ... in
"-", , . , , , Haskell , Ocaml .
, Ocaml, Stdlib
where , , , . , List.mapi
List.rev_map
. , , Ocaml , , - graph rewriting . , Ocaml where
, , Haskell let ... in
.
Thus, like good engineering works, Ocaml and Haskell create a synergy of syntax and semantics. Binding guidelines let
and where
play a role, emphasizing emphasizing linear psevdoimperativnuyu and "lazy" (graph reduction) performance model. They also work well with your preferred application writing style and associated module system.