Lojic Technologies

Programming in Standard ML – Part 2

leave a comment »

Table of Contents

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:
(val1, … ,valn)
An n-tuple is a value of a product type of the form:
typ1* … *typn
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:

  1. A variable pattern of the form var : typ
  2. A tuple pattern of the form (pat1, …, patn), where each pati is a pattern. This includes as a special case the null-tuple pattern, ()
  3. 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:
{ lab1:typ1, …, labn:typn}
A record value has the form:
{ lab1=val1, …, labn=valn}
A record pattern has the form:
{ lab1=pat1, …, labn=patn}

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 {lab1,…labn} which stands for { lab1=var1, …, labn=varn} 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!

Written by Brian Adkins

May 2, 2009 at 8:51 pm

Posted in programming

Tagged with

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: