Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does the `and` keyword mean in OCaml?

Tags:

syntax

ocaml

I'm mystified by the and keyword in OCaml. Looking through this code, I see

type env = {
    (* fields for a local environment described here *)
}

and genv {
    (* fields for a global environment here *)
}

then later,

let rec debug stack env (r, ty) = (* a function definition *)

and debugl stack env x = (* another function definition *)

What's going on here? Does the and keyword just copy the last type, let, or let rec statement? Is there such thing as an and rec statement? Why would I want to use and instead of just typing let or type, making my code less brittle to refactoring? Is there anything else I should know about?

like image 624
Jeff Hemphill Avatar asked Aug 10 '16 22:08

Jeff Hemphill


People also ask

How do you use keyword in OCaml?

The best way to look at it is that in is not a separate keyword. Instead, there's an expression that looks like let v = expr1 in expr2 . This is the way in OCaml to define a "local" variable.

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.

How do you specify types in OCaml?

OCaml has two ways of specifying types, they can be done inline: let intEq (x : int) (y : int) : bool = ... I believe the latter is preferred, since it more cleanly separates the specification (type) from the implementation (code). Show activity on this post.

What does cons mean in OCaml?

Cons (::) is a constructor, constructors can not be infix operators.


1 Answers

The and keyword is used either to avoid multiple let (first example, I never use it for this but why not) or for mutually recursive definitions of types, functions, modules...

As you can see in your second example :

let rec debug stack env (r, ty) =
   ...
   | Tunresolved tyl -> o "intersect("; debugl stack env tyl; o ")"
   ...
 
 and debugl stack env x =
   ...
   | [x] -> debug stack env x
   ...

debug calls debugl and vice versa. So the and is allowing that.

[EDIT] It bothered me not to give a proper example so here is one example that you'll often see :

let rec is_even x =
  if x = 0 then true else is_odd (x - 1)
and is_odd x =
  if x = 0 then false else is_even (x - 1)

(* second version *)

let rec is_even x =
  x = 0 || is_odd (x - 1)
and is_odd x =
  x <> 0 && is_even (x - 1)

(You can find this example here)

For mutually recursive types, it's harder to find a configuration but following this wikipedia page we would define trees and forests as follow

 type 'a tree = Empty | Node of 'a * 'a forest
 and 'a forest = Nil | Cons of 'a tree * 'a forest

As an example, a forest composed of the empty tree, the singleton tree labeled a and a two nodes tree with labels b and c would then be represented as :

 let f1 = Cons (Empty, (* Empty tree *)
             Cons (Node ('a',  (* Singleton tree *)
                         Nil), (* End of the first tree *)
                   Cons (Node ('b', (* Tree composed by 'b'... *)
                               Cons (Node ('c', (* and 'c' *)
                                           Nil), 
                                     Nil)
                           ),
                         Nil (* End ot the second tree *)
                     )
               )
         );;
  

And the size function (counting the number of nodes in the forest) would be :

let rec size_tree = function
  | Empty -> 0
  | Node (_, f) -> 1 + size_forest f
and size_forest = function
  | Nil -> 0
  | Cons (t, f) -> size_tree t + size_forest f

And we get

# size_forest f1;;
- : int = 3
like image 134
Lhooq Avatar answered Sep 22 '22 09:09

Lhooq