diff options
Diffstat (limited to 'ocaml.html.markdown')
-rw-r--r-- | ocaml.html.markdown | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/ocaml.html.markdown b/ocaml.html.markdown new file mode 100644 index 00000000..02435e4d --- /dev/null +++ b/ocaml.html.markdown @@ -0,0 +1,377 @@ +--- +language: OCaml +contributors: + - ["Daniil Baturin", "http://baturin.org/"] +--- + +OCaml is a strictly evaluated functional language with some imperative +features. + +Along with StandardML and its dialects it belongs to ML language family. +F# is also heavily influenced by OCaml. + +Just like StandardML, OCaml features both an interpreter, that can be +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 is strongly and statically typed, but instead of using manually written +type annotations, it infers types of expressions using Hindley-Milner algorithm. +It makes type annotations unnecessary in most cases, but can be a major +source of confusion for beginners. + +When you are in the top level loop, OCaml will print the inferred type +after you enter an expression. + +``` +# let inc x = x + 1 ;; +val inc : int -> int = <fun> +# let a = 99 ;; +val a : int = 99 +``` + +For a source file you can use "ocamlc -i /path/to/file.ml" command +to print all names and type signatures. + +``` +$ cat sigtest.ml +let inc x = x + 1 +let add x y = x + y + +let a = 1 + +$ ocamlc -i ./sigtest.ml +val inc : int -> int +val add : int -> int -> int +val a : int +``` + +Note that type signatures of functions of multiple arguments are +written in curried form. A function that takes multiple arguments can be +represented as a composition of functions that take only one argument. +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 ***) + +(* Comments are enclosed in (* and *). It's fine to nest comments. *) + +(* There are no single-line comments. *) + + +(*** Variables and functions ***) + +(* Expressions can be separated by a double semicolon symbol, ";;". + In many cases it's redundant, but in this tutorial we use it after + every expression for easy pasting into the interpreter shell. + Unnecessary use of expression separators in source code files + is often considered to be a bad style. *) + +(* Variable and function declarations use "let" keyword. *) +let x = 10 ;; + +(* OCaml allows single quote characters in identifiers. + Single quote doesn't have a special meaning in this case, it's often used + in cases when in other languages one would use names like "foo_tmp". *) +let foo = 1 ;; +let foo' = foo * 2 ;; + +(* Since OCaml compiler infers types automatically, you normally don't need to + specify argument types explicitly. However, you can do it if + you want or need to. *) +let inc_int (x: int) : int = x + 1 ;; + +(* One of the cases when explicit type annotations may be needed is + resolving ambiguity between two record types that have fields with + the same name. The alternative is to encapsulate those types in + modules, but both topics are a bit out of scope of this + tutorial. *) + +(* You need to mark recursive function definitions as such with "rec" keyword. *) +let rec factorial n = + if n = 0 then 1 + else n * factorial (n-1) +;; + +(* Function application usually doesn't need parentheses around arguments *) +let fact_5 = factorial 5 ;; + +(* ...unless the argument is an expression. *) +let fact_4 = factorial (5-1) ;; +let sqr2 = sqr (-2) ;; + +(* Every function must have at least one argument. + Since some funcions naturally don't take any arguments, there's + "unit" type for it that has the only one value written as "()" *) +let print_hello () = print_endline "hello world" ;; + +(* Note that you must specify "()" as argument when calling it. *) +print_hello () ;; + +(* Calling a function with insufficient number of arguments + does not cause an error, it produces a new function. *) +let make_inc x y = x + y ;; (* make_inc is int -> int -> int *) +let inc_2 = make_inc 2 ;; (* inc_2 is int -> int *) +inc_2 3 ;; (* Evaluates to 5 *) + +(* You can use multiple expressions in function body. + The last expression becomes the return value. All other + expressions must be of the "unit" type. + This is useful when writing in imperative style, the simplest + form of it is inserting a debug print. *) +let print_and_return x = + print_endline (string_of_int x); + x +;; + +(* Since OCaml is a functional language, it lacks "procedures". + Every function must return something. So functions that + do not really return anything and are called solely for their + side effects, like print_endline, return value of "unit" type. *) + + +(* Definitions can be chained with "let ... in" construct. + This is roughly the same to assigning values to multiple + variables before using them in expressions in imperative + languages. *) +let x = 10 in +let y = 20 in +x + y ;; + +(* Alternatively you can use "let ... and ... in" construct. + This is especially useful for mutually recursive functions, + with ordinary "let .. in" the compiler will complain about + unbound values. *) +let rec + is_even = function + | 0 -> true + | n -> is_odd (n-1) +and + is_odd = function + | 0 -> false + | n -> is_even (n-1) +;; + +(* Anonymous functions use the following syntax: *) +let my_lambda = fun x -> x * x ;; + +(*** Operators ***) + +(* There is little distintion between operators and functions. + Every operator can be called as a function. *) + +(+) 3 4 (* Same as 3 + 4 *) + +(* There's a number of built-in operators. One unusual feature is + that OCaml doesn't just refrain from any implicit conversions + between integers and floats, it also uses different operators + for floats. *) +12 + 3 ;; (* Integer addition. *) +12.0 +. 3.0 ;; (* Floating point addition. *) + +12 / 3 ;; (* Integer division. *) +12.0 /. 3.0 ;; (* Floating point division. *) +5 mod 2 ;; (* Remainder. *) + +(* Unary minus is a notable exception, it's polymorphic. + However, it also has "pure" integer and float forms. *) +- 3 ;; (* Polymorphic, integer *) +- 4.5 ;; (* Polymorphic, float *) +~- 3 (* Integer only *) +~- 3.4 (* Type error *) +~-. 3.4 (* Float only *) + +(* You can define your own operators or redefine existing ones. + Unlike SML or Haskell, only selected symbols can be used + for operator names and first symbol defines associativity + and precedence rules. *) +let (+) a b = a - b ;; (* Surprise maintenance programmers. *) + +(* More useful: a reciprocal operator for floats. + Unary operators must start with "~". *) +let (~/) x = 1.0 /. x ;; +~/4.0 (* = 0.25 *) + + +(*** Built-in datastructures ***) + +(* Lists are enclosed in square brackets, items are separated by + semicolons. *) +let my_list = [1; 2; 3] ;; + +(* Tuples are (optionally) enclosed in parentheses, items are separated + by commas. *) +let first_tuple = 3, 4 ;; (* Has type "int * int". *) +let second_tuple = (4, 5) ;; + +(* Corollary: if you try to separate list items by commas, you get a list + with a tuple inside, probably not what you want. *) +let bad_list = [1, 2] ;; (* Becomes [(1, 2)] *) + +(* You can access individual list items with the List.nth function. *) +List.nth my_list 1 ;; + +(* There are higher-order functions for lists such as map and filter. *) +List.map (fun x -> x * 2) [1; 2; 3] ;; +List.filter (fun x -> if x mod 2 = 0 then true else false) [1; 2; 3; 4] ;; + +(* You can add an item to the beginning of a list with the "::" constructor + often referred to as "cons". *) +1 :: [2; 3] ;; (* Gives [1; 2; 3] *) + +(* Arrays are enclosed in [| |] *) +let my_array = [| 1; 2; 3 |] ;; + +(* You can access array items like this: *) +my_array.(0) ;; + + +(*** Strings and characters ***) + +(* Use double quotes for string literals. *) +let my_str = "Hello world" ;; + +(* Use single quotes for character literals. *) +let my_char = 'a' ;; + +(* Single and double quotes are not interchangeable. *) +let bad_str = 'syntax error' ;; (* Syntax error. *) + +(* This will give you a single character string, not a character. *) +let single_char_str = "w" ;; + +(* Strings can be concatenated with the "^" operator. *) +let some_str = "hello" ^ "world" ;; + +(* Strings are not arrays of characters. + You can't mix characters and strings in expressions. + You can convert a character to a string with "String.make 1 my_char". + There are more convenient functions for this purpose in additional + libraries such as Core.Std that may not be installed and/or loaded + by default. *) +let ocaml = (String.make 1 'O') ^ "Caml" ;; + +(* There is a printf function. *) +Printf.printf "%d %s" 99 "bottles of beer" ;; + +(* Unformatted read and write functions are there too. *) +print_string "hello world\n" ;; +print_endline "hello world" ;; +let line = read_line () ;; + + +(*** User-defined data types ***) + +(* You can define types with the "type some_type =" construct. Like in this + useless type alias: *) +type my_int = int ;; + +(* More interesting types include so called type constructors. + Constructors must start with a capital letter. *) +type ml = OCaml | StandardML ;; +let lang = OCaml ;; (* Has type "ml". *) + +(* Type constructors don't need to be empty. *) +type my_number = PlusInfinity | MinusInfinity | Real of float ;; +let r0 = Real (-3.4) ;; (* Has type "my_number". *) + +(* Can be used to implement polymorphic arithmetics. *) +type number = Int of int | Float of float ;; + +(* Point on a plane, essentially a type-constrained tuple *) +type point2d = Point of float * float ;; +let my_point = Point (2.0, 3.0) ;; + +(* Types can be parameterized, like in this type for "list of lists + of anything". 'a can be substituted with any type. *) +type 'a list_of_lists = 'a list list ;; +type int_list_list = int list_of_lists ;; + +(* Types can also be recursive. Like in this type analogous to + built-in list of integers. *) +type my_int_list = EmptyList | IntList of int * my_int_list ;; +let l = IntList (1, EmptyList) ;; + + +(*** Pattern matching ***) + +(* Pattern matching is somewhat similar to switch statement in imperative + languages, but offers a lot more expressive power. + + Even though it may look complicated, it really boils down to matching + an argument against an exact value, a predicate, or a type constructor. + The type system is what makes it so powerful. *) + +(** Matching exact values. **) + +let is_zero x = + match x with + | 0 -> true + | _ -> false (* The "_" pattern means "anything else". *) +;; + +(* Alternatively, you can use the "function" keyword. *) +let is_one = function +| 1 -> true +| _ -> false +;; + +(* Matching predicates, aka "guarded pattern matching". *) +let abs x = + match x with + | x when x < 0 -> -x + | _ -> x +;; + +abs 5 ;; (* 5 *) +abs (-5) (* 5 again *) + +(** Matching type constructors **) + +type animal = Dog of string | Cat of string ;; + +let say x = + match x with + | Dog x -> x ^ " says woof" + | Cat x -> x ^ " says meow" +;; + +say (Cat "Fluffy") ;; (* "Fluffy says meow". *) + +(** Traversing datastructures with pattern matching **) + +(* Recursive types can be traversed with pattern matching easily. + Let's see how we can traverse a datastructure of the built-in list type. + Even though the built-in cons ("::") looks like an infix operator, + it's actually a type constructor and can be matched like any other. *) +let rec sum_list l = + match l with + | [] -> 0 + | head :: tail -> head + (sum_list tail) +;; + +sum_list [1; 2; 3] ;; (* Evaluates to 6 *) + +(* Built-in syntax for cons obscures the structure a bit, so we'll make + our own list for demonstration. *) + +type int_list = Nil | Cons of int * int_list ;; +let rec sum_int_list l = + match l with + | Nil -> 0 + | Cons (head, tail) -> head + (sum_int_list tail) +;; + +let t = Cons (1, Cons (2, Cons (3, Nil))) ;; +sum_int_list t ;; + +``` + +## Further reading + +* Visit the official website to get the compiler and read the docs: <http://ocaml.org/> +* Try interactive tutorials and a web-based interpreter by OCaml Pro: <http://try.ocamlpro.com/> +* Read "OCaml for the skeptical" course: <http://www2.lib.uchicago.edu/keith/ocaml-class/home.html> |