
Notes of Programming Languages, Part A by Dan Grossman, University of Washington in Coursera.
command
- C-x C-f: find file
- C-x C-s: save
- C-c C-s Enter, use “foo.sml” (Its type is unit and its result is () (the only value of type unit), but its effect is to include all the bindings in the file “foo.sml”)
- not reusing
useon a file without restarting the ERPL - C-d: exit
- The REPL: Read-Eval-Print-Loop
Basic
- SML Style Guide
- The most important commands in Emacs
- definitions for expressions: syntax, type-checking rules, evaluation rules
- Variables are Immutable Bindings are immutable. Given
val x = 8+9;we produce a dynamic environment where x maps to 17. In this environment, x will always map to 17; there is no “assignment statement” in ML for changing what x maps to. You can have another binding later, sayval x = 19;, but that just creates a different environment where the later binding for x shadows the earlier one. - minus5: ~5
- divide: x div y
Real.fromInt 2;: int -> real=<>can be used with any “equality type” but not withreal- Evaluation: A function is a value!
- Pairs and Other Tuples
Lists
Usages
- [] can have type
t listlist for any type- SML uses type
'a listto indicate this (“quote a” or “alpha”)
- SML uses type
e1::e2null eevalueates to true if and only if e evaluates to []null : 'a list -> bool
- If e evaluetes to [v1, v2,…, vn] then
hd eevaluates to v1'hd : 'a list -> 'a- (raise exception if e evalutes to [])
- If e evaluetes to [v1, v2,…, vn] then
tl eevaluates to [v2, …, vn]tl : 'a list -> 'a list- (raise exception if e evaluates to [])
- Notice result is a list
List Functions
use recursion
Let Expression
let b1 b2 ... bn in e end
Local val definitions need to be between let and in
Nested Functions
|
|
Functions can use bindings in the environment where they are defined:
- Binding from “outer” environments such as parameters to the outer function
- Earlier bindings in the let-expression
Avoid Repeated Computation: Saving recursive results in local bindings is essential
Options
- Motivating Options Having
maxreturn 0 for the empty list is really awful- Could raise an exception
- Could return a zero-element or one-element list
t optionis a type for any type t- Building
NONEhas type'a optionSOME ehas typet optionif e has type t
- Accessing
isSomehas typea option -> bool- ‘valOf’ has type
'a option -> 'a(exception if givenNONE)
|
|
In the above function, we call isSome tl_ans checking for none every time but none case is only for the empty list. The following version is a little cleaner.
run:
Lack of Mutation and Benefits Thereof
- In ML, there is no way to change the contents of a binding, a tuple, or a list. If x maps to some value like the list of pairs [(3,4),(7,9)] in some environment, then x will forever map to that list in that environment. There is no assignment statement that changes x to map to a different list.
- Having immutable data is probably the most important “non-feature” a anguage can have, and it is one of the main contributions of functional programming.
- A big advantages to immutable data: it makes sharing and aliasing irrelevant
The Pieces of a Programming Language
Five different things
- Syntax: How do you write language constructs?
- Semantics: What do programs mean? (Evaluation rules)
- Idioms: What are typical patterns for using language features to express your computation?
- Libraries: What facilities does the language(or a well-known project) provide “standard”:
- Tools: What do language implementations provide to make your job easier?
Section2
Conceptual Ways to Build New Types
Base types: int bool unit char…
Compound types: tuples lists options…
Any decent programming language provides these building blocks in some way:
- “Each-of”: A compound type t describes values that contain each of values of type t1, t2, …, and tn.
- “One-of”: A compound type t describes values that contain a value of one of the types t1, t2, …, or tn.
- “Self-reference”: A compound type t may refer to itself in its definition in order to describe recursive data structures like lists and trees.
tuples are particular ways of writing paticular records
Example: - Tuples build each-of types:
int * boolcontains anintand abool - Options build one-of types:
int optioncontains anintor it contains no data - Lists use all three building blocks:
int listcontains anintand anotherint listor it contains no data Records: Another Approach to “Each-of” Types
- Record values have fields (any name) holding values
{f1 = v1, ..., fn = vn} - Record types have fields (and name) holding values
{f1 : t1, ..., fn : tn} - The order of fields in a record value or type never matters (REPL alphabetizes fields just for consistency)
- Building records:
{f1 = e1, ..., fn = en} - Accessing pieces:
#myfieldname e
By Name vs. By Position, Syntactic Sugar, and The Truth About Tuples
- Records are “by name” and tuples are “by position.”
(e1, ..., en)is another way of writing{1=e1, ..., n=en}t1*...*tnis another way of writing{1:t1, ..., n:tn}- “Tuples are just syntactic sugar for records with field named 1, 2, …, n”
Datatype Bindings: Our Own “One-of” Types
Datatype bindings, our third kind of binding after variable bindings and function bindings
Build datatype values
|
|
- Adds a new type
mytypeto the environment - Adds constructors to the environment:
TwoInts,StrandPizza - A constructor is (among other things), a function that makes values of the new type (or is a value of the new type):
|
|
Access a datatype value
- Check what variant it is (what constructor made it) <-
nullandisSome - Extract the data (if that variant has any) <-
hd,tlandvalOf