Standard ML Keywords (from the lambda-in-SML material)

A compact cheat sheet of common SML keywords you’ll see in the lambda-calculus SML code, with short explanations and rough Python parallels.

Core definition keywords

val binding

What it does: Binds a value to a name (like a variable or constant).

(* SML *)
val x = 3;
val y = x + 2;
# Python
x = 3
y = x + 2
fun function definition

What it does: Defines a named function, often with pattern matching on arguments.

(* SML *)
fun add (a, b) = a + b;

fun fact 0 = 1
  | fact n = n * fact (n - 1);
# Python
def add(a, b):
    return a + b

def fact(n):
    if n == 0:
        return 1
    else:
        return n * fact(n - 1)
datatype algebraic data type

What it does: Defines a new sum type with multiple constructors (used heavily for lambda terms).

(* SML *)
datatype LEXP =
    ID  of string
  | LAM of string * LEXP
  | APP of LEXP * LEXP;
# Python (roughly, using classes)
class ID:
    def __init__(self, name):
        self.name = name

class LAM:
    def __init__(self, var, body):
        self.var = var
        self.body = body

class APP:
    def __init__(self, f, arg):
        self.f = f
        self.arg = arg
type type alias

What it does: Creates a new name for an existing type (a synonym, not a new type).

(* SML *)
type Var = string;
type Env = (Var * int) list;
# Python (no real type alias at runtime, but we can annotate)
Var = str
Env = list[tuple[Var, int]]

Anonymous functions and local bindings

fn anonymous function

What it does: Creates an anonymous (lambda) function.

(* SML *)
val inc = fn x => x + 1;
val apply = fn (f, x) => f x;
# Python
inc = lambda x: x + 1

def apply(f, x):
    return f(x)
let / in / end local scope

What it does: Introduces local definitions and an expression that uses them.

(* SML *)
val result =
  let
    val x = 2
    val y = 3
  in
    x * y
  end;
# Python (using a block or inner function)
def compute():
    x = 2
    y = 3
    return x * y

result = compute()

Control flow and pattern matching

if / then / else conditional

What it does: Standard conditional expression (must have an else branch).

(* SML *)
val sign =
  if x > 0 then 1
  else if x < 0 then ~1
  else 0;
# Python
if x > 0:
    sign = 1
elif x < 0:
    sign = -1
else:
    sign = 0
case / of pattern matching

What it does: Matches a value against patterns (especially for datatypes).

(* SML *)
fun eval (ID x) = ...
  | eval (LAM (x, e)) = ...
  | eval (APP (e1, e2)) = ...;

(* or with case *)
fun eval e =
  case e of
      ID x => ...
    | LAM (x, body) => ...
    | APP (e1, e2) => ...;
# Python (manual pattern matching)
def eval(expr):
    if isinstance(expr, ID):
        ...
    elif isinstance(expr, LAM):
        ...
    elif isinstance(expr, APP):
        ...

Recursion and logical operators

rec recursive binding

What it does: Used with fun or val to define recursive functions/values.

(* SML *)
fun fact 0 = 1
  | fact n = n * fact (n - 1);

(* or explicitly *)
val rec fact =
  fn 0 => 1
   | n => n * fact (n - 1);
# Python
def fact(n):
    if n == 0:
        return 1
    return n * fact(n - 1)
andalso / orelse / not boolean operators

What they do: Short-circuit logical operators and negation.

(* SML *)
val b1 = (x > 0) andalso (y > 0);
val b2 = (x = 0) orelse (y = 0);
val b3 = not b1;
# Python
b1 = (x > 0) and (y > 0)
b2 = (x == 0) or (y == 0)
b3 = not b1

Exceptions and error handling

exception define exception

What it does: Declares a new exception type.

(* SML *)
exception EvalError;
exception UnboundVar of string;
# Python
class EvalError(Exception):
    pass

class UnboundVar(Exception):
    def __init__(self, name):
        self.name = name
raise throw exception

What it does: Raises an exception.

(* SML *)
raise EvalError;
raise UnboundVar "x";
# Python
raise EvalError()
raise UnboundVar("x")
handle catch exception

What it does: Catches exceptions and provides alternative behavior.

(* SML *)
val result =
  (eval e)
  handle UnboundVar x => 0
       | EvalError => ~1;
# Python
try:
    result = eval(e)
except UnboundVar as ex:
    result = 0
except EvalError:
    result = -1

Modules (you may see them in larger code)

structure / signature / functor modules

What they do: Define modules (structure), module interfaces (signature), and parameterized modules (functor).

(* SML *)
signature LEXP_SIG =
sig
  datatype LEXP = ...
  val eval : LEXP -> LEXP
end;

structure Lexp : LEXP_SIG =
struct
  datatype LEXP = ...
  fun eval e = ...
end;
# Python (rough analogy: modules and classes)
# In a file lexp.py
class LEXP:
    ...

def eval(expr):
    ...

Quick recap

  • SML Keywords - Quiz