## Programming in Standard ML – Part 2

## Chapter 4 – Functions

Lambda expressions are written as:

fn var : typ => exp

For example:

fn x : real => Math.sqrt (Math.sqrt x) (fn x : real => Math.sqrt (Math.sqrt x)) (16.0) val fourthroot : real -> real = fn x : real => Math.sqrt (Math.sqrt x) fourthroot 16.0

ML provides a special syntax for function bindings that’s more concise:

fun fourthroot (x:real):real = Math.sqrt (Math.sqrt x)

By experimenting (I expect this is covered later), I found the following is sufficient due to type inference:

fun fourthroot x = Math.sqrt (Math.sqrt x)

Local val bindings may shadow parameters and other val bindings. For example, in the following, the last occurrence of x refers to the parameter of h, but the preceding two occurrences of x refer to the local binding with a value of 2.0:

fun h(x:real):real = let val x:real = 2.0 in x+x end * x

## Chapter 5 – Products and Records

The *n-tuple* is the simplest form of aggregate data structure. They are of the form:

(val_{1}, … ,val_{n})

An *n*-tuple is a value of a *product type* of the form:

*typ _{1}** … *

*typ*

_{n}For example:

val pair : int * int = (2, 3) val triple : int * real * string = (2, 2.0, "2") val pair_of_pairs : (int * int) * (real * real) = ((2,3),(2.0,3.0))

A 0-tuple, also known as a *null tuple*, is the empty sequence of values, ( ). It is a value of type unit. 1-tuples are absent from the language.

### Tuple Patterns

We can use pattern matching to extract portions of an n-tuple. For example, in the code snippet below, r will be equal to 3.14. Underscores indicate “don’t care” positions:

val foo : (int * string) * (real * char) = ((7,"hello"),(3.14,#"z")) val ((_, _), (r:real, _)) = foo

We can give names to the first and second components of the pair – using the REPL:

- val (is:int*string,rc:real*char) = foo; val is = (7,"hello") : int * string val rc = (3.14,#"z") : real * char

A pattern is one of three forms:

- A
*variable pattern*of the form*var : typ* - A
*tuple pattern*of the form (*pat*), where each_{1}, …, pat_{n}*pat*is a pattern. This includes as a special case the null-tuple pattern, ()_{i} - A
*wildcard pattern*of the form _

### Record Types

Tuples can become more difficult to use as the number of elements increases. Record types allow labeling each component. A record *type* has the form:

{ lab_{1}:typ_{1}, …, lab_{n}:typ_{n}}

A record *value* has the form:

{ lab_{1}=val_{1}, …, lab_{n}=val_{n}}

A record *pattern* has the form:

{ lab_{1}=pat_{1}, …, lab_{n}=pat_{n}}

For example, the record type hyperlink is defined as follows:

type hyperlink = { protocol : string, address : string, display : string }

The following record binding defines a variable of type hyperlink:

val mailto : hyperlink = { protocol = "mailto", address = "foo@bar.com", display = "Brian Adkins" }

The following record binding:

val { protocol=prot, display=disp, address=addr } = mailto

decomposes into the three variable bindings:

val prot = "mailto" val addr = "foo@bar.com" val disp = "Brian Adkins"

We can use wildcard to extract selected fields:

val {protocol=prot, address=_, display=_ } = mailto

However, this isn’t very helpful with many fields, so we can use *ellipsis patterns*:

val {protocol=prot, ... } = mailto

ML provides an abbreviated form of record pattern {lab_{1},…lab_{n}} which stands for { lab_{1}=var_{1}, …, lab_{n}=var_{n}} where the variables have the same name as the corresponding labels. For example, the following:

val { protocol, address, display } = mailto

decomposes into these bindings:

val protocol = "mailto" val address = "foo@bar.com" val display = "Brian Adkins"

### Multiple Arguments and Multiple Results

fun dist (x:real, y:real):real = sqrt (x*x + y*y)

Keyword parameters are supported through record patterns:

fun dist’ {x=x:real, y=y:real} = sqrt (x*x + y*y)

Invoked as follows:

dist' {x=2.0,y=3.0}

Functions with multiple results may be thought of as functions yield tuples (or records).

fun dist2 (x:real, y:real):real*real = (sqrt (x*x+y*y), abs(x-y))

*Sharp notation* allows us to conveniently access the Nth item in a tuple.

- val foo = (3,7,5,2); val foo = (3,7,5,2) : int * int * int * int - #3 foo; val it = 5 : int

A similar notation is used for record field selection:

- val foo = { name = "Brian", phone = "555-1212" }; val foo = {name="Brian",phone="555-1212"} : {name:string, phone:string} - #name foo; val it = "Brian" : string

However, Harper states, “**Use of the sharp notation is strongly discouraged!**“

## Leave a Reply