source -> https://www.youtube.com/watch?v=A5IHFZtRfBs&list=PLre5AT9JnKShBOPeuiD9b-I4XROIJhkIU&index=6
- Syntax: How do you write language constructs?
- Semantics: What do programs mean? (Type checking, evaluation rules)
- Idioms: What are typical patterns for using language features to express your computation?
- Libraries: What facilities does the language (or a third-party project) provide as "standard"? (E.g., file access, data structures)
- Tools: What do language implementations provide to make your job easier? (E.g., top-level, debugger, GUI editor, ...)
β’ Syntax β’ Semantics:
- Type-checking rules (static semantics): produce a type, or fail with an error message
- Evaluation rules (dynamic semantics): produce a value, or exception or infinite loop
A value is an expression that does not need any further evaluation
Note : we read an expression from right to left
utop # 3110;;
- : int = 31100
(* booleans in ocaml *)
utop # true;;
- : bool = false
(* String in ocaml with concatination *)
utop # "big" ^ "red";;
- : string = "bigred"
(* type float : notice the error below *)
utop # 2.0 * 3.14;;
Error: This expression has type float but an expression was expected af type int
(* so for floating point operator we need *. dot after operators *)
utop # 2.0 *. 3.14;;
- : float = 6.28
utop # -3.0 /. 4.0;;
- : float = -0.75
utop # "So" ^ " " " "it" ^ " " ~ "goes";;
- : string = "So it goes"
utop # 1 > 2 || not (2.0 < 1.0);;
- :bool = true
β’ OCaml compiler infers types
- Compilation fails with type error if it can't (type checking is done first)
- Hard part of language design: guaranteeing compiler can infer types when program is correctly written
β’ You can manually annotate types anywhere
- Replace e with (e : t)
- Useful for diagnosing type errors
utop # (3110 : int);;
- : int = 3110
(* altough we cannot convert these types so:π *)
utop # (3110 : bool);;
Error: This expression has type int but an expression was expected of type bool
- By means of let, a variable can be assigned a value.
- The variable retains this value for ever!
utop # let seven = 3 + 4;;
val seven : int = 7
utop # seven;;
- : int = 7
π¨ Another definition of seven does not assign a new value to seven, but creates a new variable with the name seven.
# let seven = 42;;
val seven int = 42
# seven;;
-:int = 42
# let seven = "seven";;
val seven : string = "seven"
(* The old variable is now hidden (but still there)!
Apparently, the new variable may even have a different type. *)
Here we define lets as expressions and not definition so we can do more complex actions at once π
utop # let a = 0 in a;;
- : int = 0
utop # let b = 1 in 2 * b;;
- : int = 2
utop # a;;
Error: Unbound value a
(* now a and also b are outside the scope *)
utop # let c = 3 in (let d = 4 in c + d);;
- : int = 7
utop # let e = 5 in (e = 6 in e);;
- : int = 6
the name of variable shouldn't intrinsically matter
To ensure name irrelevance in programs, stop substituting when you reach a binding of the same name
utop # let x = 5 in ((let x = 6 in x) + x);;
- : int = 11
utop # if true then "yay" else "boo";;
- : string = "boo"
(* But we cant use different types as the results *)
utop # if true then "yay" else 1;;
Error: This expression has type int but an expression was expected of type
string
if el then e2 else e3
Evaluation:
- if el evaluates to true, and if e2 evaluates to v, then if el then e2 else e3 evaluates to v
- if el evaluates to false, and if e3 evaluates to v, then if el then e2 else e3 evaluates to v
Type checking: if el has type bool and e2 has type t and e3 has type t then if el then e2 else e3 has type t
Functions are values !
Can use them anywhere we use values: β’ Functions can take functions as arguments β’ Functions can return functions as results
Syntax: fun x1 ...... xn -> e
utop # (fun x -> x +1);;
- : int -> int = <fun>
(* the "<" bracket means utop cant print the value of this type , becaues this is already compiled and exists as bits of memory and no longer in original form *)
Evaluation of e0 el ... en:
- Evaluate subexpressions: e0 ==> v0, β’ , en ==> vn v0 must be a function: fun x1 ... xn -> e
- Substitute vi for xi in e yielding new expression e'. Evaluate it: e' ==> v
- Result is v
(fun x -> x + 1) (2+3)
(* step 1 is done since the anonym func is already a value *)
(fun x -> x + 1) (5)
(* also evaluate the argument values here (2+3) = 5 *)
5 + 1
(* step 2: subsitute the argument to the func *)
6
(* step 3: 6 is result *)
(* One more example *)
(fun x y -> x - y) (3*1) (3-1)
(fun x y -> x - y) (3) (2)
3 - 2
1
Latter is syntactic sugar β’ not necessary β’ makes language "sweeter"
utop # let square = fun x -> x * x;;
val square : int -> int = <fun>
(* simplified *)
utop # let square x = x * x;;
val square : int -> int = <fun>