let x = 3;; (* just at utop the ;; *) let y = 3.;; (* float *) let z = y +. 4.;; (* float operators should have . (+., -. etc)*) let x = "string";; let y = [1;2;3];; (* list of ints *) let y = 1 :: 2 :: 3 :: [];; (* same list of ints *) let tp = (1,2,3);; (* create tuple *) let tp = 1,2,3;; (* same tuple *) let (x, y, z) = tp;; (*unpacking tuple*) let square x = x * x;; (* function square *) (* dist function using unpacking *)List.map languages ~f:String.length;; - : int list = [5; 4; 1] let distance (x1, x2) (y1, y2) = List.map languages ~f:String.length;; - : int list = [5; 4; 1] Float.sqrt((x1 -. x2) **. 2. +. (y1 -. y2) **. 2.);;List.map languages ~f:String.length;; - : int list = [5; 4; 1] (* length of the list *) let list = [1;2;3];; List.length list;; let languages = ["ocaml";"c"]; List.map languages ~f:String.length;; (* create a match pattern for our list. if our list is passed, the first element is returned, if the list is empty we have a default value*) let fav_lang languages = match languages with | first :: the_rest -> first | [] -> "Default val" let rec sum l = match l with | [] -> 0 (* base case *) | hd :: tl -> hd + sum tl (* inductive case *);; sum [1;2;3];; (* the sum of all nums in the list *) (* note that HD is the head of the list and TL is the tail *) (* example factorial passing [3,2,1] for example *) let rec factorial l = match l with | [1] -> 1 | hd :: tl -> hd * factorial tl | [] -> 0;; let rec remove_sequential_duplicates list = match list with | [] -> [] | [x] -> [x] | first :: second :: tl -> if first = second then remove_sequential_duplicates (second :: tl) else first :: remove_sequential_duplicates (second :: tl);; remove_sequential_duplicates [1;1;2;3;3;4;4;1;1;1];; (* [1;2;3;4] *) (* options: The function divide either returns None if the divisor is zero, or Some of the result of the division otherwise. Some and None are constructors that let you build optional values, just as :: and [] let you build lists. You can think of an option as a specialized list that can only have zero or one elements. *) let divide x y = if y = 0 then None else Some (x / y);; let downcase_extension filename = match String.rsplit2 filename ~on:'.' with (*split the string at the . char*) | None -> filename (* if nothing after the . just return the filename *) | Some (base,ext) -> (* since the split return the base and the extension, we return the base, get them together with . and lowercase *) base ^ "." ^ String.lowercase ext;; (* ^ is concatenation operator *) (* here we map each extension in our list with our new fn *) List.map ~f:downcase_extension [ "Hello_World.TXT"; "Hello_World.txt"; "Hello_World" ];; (* creating new data types *) type point2d = { x : float; y : float; };; let p = { x = 3.; y = -4. };; (* val p : point2d = {x = 3.; y = -4.} *) (* we can access these types using pattern matching *) let magnitude { x; y } = Float.sqrt (x **. 2. +. y **. 2.);; (* val magnitude : point2d -> float = *) let distance v1 v2 = magnitude { x = v1.x -. v2.x; y = v1.y -. v2.y };; (* we can compose larger types *) type circle_desc = { center: point2d; radius: float } type rect_desc = { lower_left: point2d; width: float; height: float } type segment_desc = { endpoint1: point2d; endpoint2: point2d } (* We also have Variant types, that we can combine multiple objects of the other types as a description of a multi - object scene, a unified way of representing those object *) type scene_el = | Circle of circle_desc | Rect of rect_desc | Segment of segment_desc (* Now we can write a function to test wether a point is in the interior of some element of a list of scene_els.*) let is_inside_scene_element point scene_element = let open Float.O in match scene_element with | Circle { center; radius } -> distance center point < radius | Rect { lower_left; width; height } -> point.x > lower_left.x && point.x < lower_left.x + width && point.y > lower_left.y && point.y < lower_left.y + height | Segment _ -> false (* here we use an anonymous function (List.exists) and the purpose of it is to check if there are any element in the list in question for which the provided function evaluates to true (in this case, to check if there is a scene element within which our point resides) *) let is_inside_scene point scene = List.exists scene ~f:(fun el -> is_inside_scene_element point el);; is_inside_scene {x=3.;y=7.} [ Circle {center = {x=4.;y= 4.}; radius = 0.5 } ];; (* Imperative programming - arrays, mutable data struct *) let numbers = [| 1; 2; 3; 4 |];; numbers.(2) <- 4;; numbers - : int array = [|1; 2; 4; 4|] (* mutable record fields -> storing a running statistical summary of a collection of nums *) type running_sum = { mutable sum: float; mutable sum_sq: float; mutable samples: int; } let mean rsum = rsum.sum /. Float.of_int rsum.samples;; let stdev rsum = Float.sqrt (rsum.sum_sq /. Float.of_int rsum.samples -. mean rsum **. 2.);; (*create returns a running_sum corresponding to the empty set, and update rsum x changes rsum to reflect the addition of x to its set of samples by updating the number of samples, the sum, and the sum of squares.*) let create () = { sum = 0.; sum_sq = 0.; samples = 0 };; let upate rsum x = rsum.samples <- rsum.samples + 1; rsum.sum <- rsum.sum +. x; rsum.sum_sq <- rsum.sum_sq +. x *. x;; let rsum = create ();; List.iter [1.;3.;2.;-7.;4.;5.] ~f: (fun x -> update rsum x);; (* refs: we can create a single mutable value using a ref - which is a record type with a single mutable field called contents *) let x = { contents = 0 };; x.contents <- x.contents + 1;; (* and we have useful functions for refs *) let x = ref 0 !x (* same as x.contents *) x := !x + 1 (* assignment *) (* no magic, refs are simply implemented like: *) type 'a ref = { mutable contents : 'a };; let ref x = { contents = x };; let (!) r = r.contents;; let (:=) r x = r.contents <- x;; (* nesting lets with LET and IN. A let paired with an in can be used to introduce a new binding within any local scope including a function body. The in marks the beginning of the scope within which the new variable can be used. *) let z = 7 in z + z;; (* and the scope of the let binding is terminated by ;; *) (* we can have multiple bindings, each one adding a new var binding to what came before *) let x = 7 in let y = x * x in x + y;; (* we can also use for and while loops *) let permute array = let length = Array.length array in for i = 0 to length - 2 do (* pick a j to swap with *) let j = i + Random.int (length - i) in (* Swap i and j *) let tmp = array.(i) in array.(i) <- array.(j); array.(j) <- tmp done;; let ar = Array.init 20 ~f:(fun i -> i);; permute ar;; ar;; (* As a side note, the preceding code takes advantage of the fact that &&, OCaml’s “and” operator, short-circuits. In particular, in an expression of the form expr1&&expr2, expr2 will only be evaluated if expr1 evaluated to true. Were it not for that, then the preceding function would result in an out-of-bounds error.*) let find_first_negative_entry array = let pos = ref 0 in while let pos_is_good = !pos < Array.length array in let element_is_non_negative = array.(!pos) >= 0 in pos_is_good && element_is_non_negative do pos := !pos + 1 done; if !pos = Array.length array then None else Some !pos;; find_first_negative_entry [|1;2;0;3|];; (* Exception: Invalid_argument "index out of bounds". *)