Let vs where in Ocaml / Haskell

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.








All Articles