Programming in Standard ML – Part 1
Table of Contents
The posts in this series will be notes & highlights from working through “Programming in Standard ML” by Robert Harper. See Getting Started with Standard ML for a link to the PDF. I may not always use quotes in this series, but it should be assumed that any factual information about Standard ML that I write in this series has been obtained from the PDF above – this series is, in effect, a summarization of Robert Harper’s PDF.
Attributes of Standard ML:
- Type-safe programming language
- Statically typed
- Extensible type system
- Polymorphic type inference
- Automatic storage management
- Encourages functional (effect-free) programming
- Allows imperative (effect-ful) programming where appropriate
- Pattern matching
- Extensible exception mechanism for handling error conditions
- Expressive and flexible module system
- Portable due to its precise definition
- Portable standard basis library
Chapter 1 – Programming in Standard ML
This chapter provides a brief overview of the language by considering an implementation of a regular expression package. It was slightly more familiar to me because of my brief studies of Haskell; otherwise, I think it would’ve appeared very foreign. I prefer more of a bottom up approach as much as possible instead of looking at language features that haven’t been described.
I do think that currying & partial application are cool features. Consider the following function declaration:
val match : RegExp.regexp -> string -> bool
Coming from a non-currying background, I would describe match as a function that accepts a regular expression and a string, and returns a boolean value indicating whether the string matches the regular expression, but Robert describes it this way:
It contains a function match that, when given a regular expression, returns a function that determines whether or not a given string matches that expression.
This was one of the features that made a strong impression on me when I first started looking at functional programming languages.
Chapter 2 – Types, Values, and Effects
Computation in ML is of a somewhat different nature. The emphasis in ML is on computation by evaluation of expressions, rather than execution of commands.
An expressions has three characteristics:
- It may or may not have a type
- It may or may not have a value
- It may or may not create an effect
Effects will be ignored until chapter 13, so until then, it’s assumed that all expressions are effect-free, or pure. A type is defined by specifying three things:
- a name for the type,
- the values of the type, and
- the operations that may be performed on values of the type
- Negative numbers, as literals, are indicated with a tilde instead of a hypen e.g. ~7
- div is used for integers, / for reals
A typing assertion has the form: exp : typ For example: 3 : int 4 div 3 : int ML does not perform any implicit conversions between types. Use real(3) + 4.3, or 3 + round(4.3) Conditional expression (exp1 and exp2 must have the same type): if exp then exp1 else exp2 if not exp then exp1 else exp2
Chapter 3 – Declarations
Once a variable is bound to a value, it is bound to it for life; there is no possibility of changing the binding of a variable once it has been bound. Examples of type bindings:
type float = real type count = int and average = real
Examples of value bindings:
val m : int = 3+2 val pi : real = 3.14 and e : real = 2.17
One thing to keep in mind is that binding is not assignment. The binding of a variable never changes; once bound to a value, it is always bound to that value (within the scope of the binding). However, we may shadow a binding by introducing a second binding for a variable within the scope of the ﬁrst binding.
Limiting scope with let expressions:
let val m : int = 3 val n : int = m*m in m*n end
The following expression evaluates to 54 because the binding of m is temporarily overridden during the evaluation of the let expression, then restored upon completion of this evaluation:
val m : int = 2 val r : int = let val m : int = 3 val n : int = m*m in m*n end * m