From ca852c8b7d8f1a84da380f3ce86fcb0b6a1a5a02 Mon Sep 17 00:00:00 2001 From: Luke Tong <56455367+luke-rt@users.noreply.github.com> Date: Sun, 31 Dec 2023 07:09:15 -0500 Subject: [PATCH] [ocaml/en] Update ocaml.html.markdown (#4818) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Dune and Opam immutability by default records @ append operator ‘a option type example Tree type example more detail in pattern matching (exhaustiveness) is sorted and reverse list function examples Higher order functions transform and filter example mutable records, refs * fixed comment --- ocaml.html.markdown | 142 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 134 insertions(+), 8 deletions(-) diff --git a/ocaml.html.markdown b/ocaml.html.markdown index fcd12951..2c5e13d5 100644 --- a/ocaml.html.markdown +++ b/ocaml.html.markdown @@ -4,8 +4,8 @@ filename: learnocaml.ml contributors: - ["Daniil Baturin", "http://baturin.org/"] - ["Stanislav Modrak", "https://stanislav.gq/"] + - ["Luke Tong", "https://lukert.me/"] --- - OCaml is a strictly evaluated functional language with some imperative features. @@ -17,6 +17,8 @@ used interactively, and a compiler. The interpreter binary is normally called `ocaml` and the compiler is `ocamlopt`. There is also a bytecode compiler, `ocamlc`, but there are few reasons to use it. +It also includes a package manager, `opam`, and a build system, `dune`. + It is strongly and statically typed, but instead of using manually written type annotations, it infers types of expressions using the [Hindley-Milner](https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system) @@ -58,7 +60,6 @@ The `f(x,y) = x + y` function from the example above applied to arguments 2 and 3 is equivalent to the `f0(y) = 2 + y` function applied to 3. Hence the `int -> int -> int` signature. - ```ocaml (*** Comments ***) @@ -76,6 +77,7 @@ Hence the `int -> int -> int` signature. is often considered to be a bad style. *) (* Variable and function declarations use the "let" keyword. *) +(* Variables are immutable by default in OCaml *) let x = 10 ;; (* OCaml allows single quote characters in identifiers. @@ -227,6 +229,10 @@ List.filter (fun x -> x mod 2 = 0) [1; 2; 3; 4] ;; often referred to as "cons". *) 1 :: [2; 3] ;; (* Gives [1; 2; 3] *) +(* Remember that the cons :: constructor can only cons a single item to the front + of a list. To combine two lists use the append @ operator *) +[1; 2] @ [3; 4] ;; (* Gives [1; 2; 3; 4] *) + (* Arrays are enclosed in [| |] *) let my_array = [| 1; 2; 3 |] ;; @@ -295,11 +301,55 @@ let my_point = Point (2.0, 3.0) ;; type 'a list_of_lists = 'a list list ;; type int_list_list = int list_of_lists ;; +(* These features allow for useful optional types *) +type 'a option = Some of 'a | None ;; +let x = Some x ;; +let y = None ;; + (* Types can also be recursive. Like in this type analogous to a built-in list of integers. *) type my_int_list = EmptyList | IntList of int * my_int_list ;; let l = IntList (1, EmptyList) ;; +(* or Trees *) +type 'a tree = + | Empty + | Node of 'a tree * 'a * 'a tree + +let example_tree: int tree = + Node ( + Node (Empty, 7, Empty), + 5, + Node (Empty, 9, Empty) + ) +(* + 5 + / \ + 7 9 +*) + +(*** Records ***) + +(* A collection of values with named fields *) + +type animal = + { + name: string; + color: string; + legs: int; + } +;; + +let cow = + { name: "cow"; + color: "black and white"; + legs: 4; + } +;; +val cow : animal + +cow.name ;; +- : string = "cow" (*** Pattern matching ***) @@ -346,6 +396,19 @@ let say x = say (Cat "Fluffy") ;; (* "Fluffy says meow". *) +(* However, pattern matching must be exhaustive *) +type color = Red | Blue | Green ;; +let what_color x = + match x with + | Red -> "color is red" + | Blue -> "color is blue" + (* Won't compile! You have to add a _ case or a Green case + to ensure all possibilities are accounted for *) +;; +(* Also, the match statement checks each case in order. + So, if a _ case appears first, none of the + following cases will be reached! *) + (** Traversing data structures with pattern matching **) (* Recursive types can be traversed with pattern matching easily. @@ -372,13 +435,76 @@ let rec sum_int_list l = let t = Cons (1, Cons (2, Cons (3, Nil))) ;; sum_int_list t ;; + +(* Heres a function to tell if a list is sorted *) +let rec is_sorted l = + match l with + | x :: y :: tail -> x <= y && is_sorted (y :: tail) + | _ -> true +;; + +is_sorted [1; 2; 3] ;; (* True *) +(* OCaml's powerful type inference guesses that l is of type int list + since the <= operator is used on elements of l *) + +(* And another to reverse a list *) +let rec rev (l: 'a list) : 'a list = + match l with + | [] -> [] + | x::tl -> (rev tl) @ [x] +;; + +rev [1; 2; 3] ;; (* Gives [3; 2; 1] *) +(* This function works on lists of any element type *) + +(*** Higher Order Functions ***) + +(* Functions are first class in OCaml *) + +let rec transform (f: 'a -> 'b) (l: 'a list) : 'b list = + match l with + | [] -> [] + | head :: tail -> (f head) :: transform f tail +;; + +transform (fun x -> x + 1) [1; 2; 3] ;; (* Gives [2; 3; 4] *) + +(** Lets combine everything we learned! **) +let rec filter (pred: 'a -> bool) (l: 'a list) : 'a list = + begin match l with + | [] -> [] + | x :: xs -> + let rest = filter pred xs in + if pred x then x :: rest else rest + end +;; + +filter (fun x -> x < 4) [3; 1; 4; 1; 5] ;; (* Gives [3; 1; 1]) *) + +(*** Mutability ***) + +(* Records and variables are immutable: you cannot change where a variable points to *) + +(* However, you can create mutable polymorphic fields *) +type counter = { mutable num : int } ;; + +let c = { num: 0 } ;; +c.num ;; (* Gives 0 *) +c.num <- 1 ;; (* <- operator can set mutable record fields *) +c.num ;; (* Gives 1 *) + +(* OCaml's standard library provides a ref type to make single field mutability easier *) +type 'a ref = { mutable contents : 'a } ;; +let counter = ref 0 ;; +!counter ;; (* ! operator returns x.contents *) +counter := !counter + 1 ;; (* := can be used to set contents *) ``` ## Further reading -* Visit the official website to get the compiler and read the docs: -* Quick tutorial on OCaml: -* Complete online OCaml v5 playground: -* An up-to-date (2022) book (with free online version) "Real World OCaml": -* Online interactive textbook "OCaml Programming: Correct + Efficient + Beautiful" from Cornell University: -* Try interactive tutorials and a web-based interpreter by OCaml Pro: +* Visit the official website to get the compiler and read the docs: [http://ocaml.org/](http://ocaml.org/) +* Quick tutorial on OCaml: [https://ocaml.org/docs/up-and-running](https://ocaml.org/docs/up-and-running) +* Complete online OCaml v5 playground: [https://ocaml.org/play](https://ocaml.org/play) +* An up-to-date (2022) book (with free online version) "Real World OCaml": [https://www.cambridge.org/core/books/real-world-ocaml-functional-programming-for-the-masses/052E4BCCB09D56A0FE875DD81B1ED571](https://www.cambridge.org/core/books/real-world-ocaml-functional-programming-for-the-masses/052E4BCCB09D56A0FE875DD81B1ED571) +* Online interactive textbook "OCaml Programming: Correct + Efficient + Beautiful" from Cornell University: [https://cs3110.github.io/textbook/cover.html](https://cs3110.github.io/textbook/cover.html) +* Try interactive tutorials and a web-based interpreter by OCaml Pro: [http://try.ocamlpro.com/](http://try.ocamlpro.com/)