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
use
on 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 list
list for any type- SML uses type
'a list
to indicate this (“quote a” or “alpha”)
- SML uses type
e1::e2
null e
evalueates to true if and only if e evaluates to []null : 'a list -> bool
- If e evaluetes to [v1, v2,…, vn] then
hd e
evaluates to v1'hd : 'a list -> 'a
- (raise exception if e evalutes to [])
- If e evaluetes to [v1, v2,…, vn] then
tl e
evaluates 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
max
return 0 for the empty list is really awful- Could raise an exception
- Could return a zero-element or one-element list
t option
is a type for any type t- Building
NONE
has type'a option
SOME e
has typet option
if e has type t
- Accessing
isSome
has 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 * bool
contains anint
and abool
- Options build one-of types:
int option
contains anint
or it contains no data - Lists use all three building blocks:
int list
contains anint
and anotherint list
or 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*...*tn
is 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
mytype
to the environment - Adds constructors to the environment:
TwoInts
,Str
andPizza
- 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) <-
null
andisSome
- Extract the data (if that variant has any) <-
hd
,tl
andvalOf