Introduction to ML A Quasi-Functional Language With Strong Typing And Type Inference.

Slides:



Advertisements
Similar presentations
More ML Compiling Techniques David Walker. Today More data structures lists More functions More modules.
Advertisements

Modern Programming Languages, 2nd ed.
ML Lists.1 Standard ML Lists. ML Lists.2 Lists A list is a finite sequence of elements. [3,5,9] ["a", "list" ] [] Elements may appear more than once [3,4]
ML Lists.1 Standard ML Lists. ML Lists.2 Lists  A list is a finite sequence of elements. [3,5,9] ["a", "list" ] []  Elements may appear more than once.
A First Look at ML.
A Third Look At ML 1. Outline More pattern matching Function values and anonymous functions Higher-order functions and currying Predefined higher-order.
Type Checking, Inference, & Elaboration CS153: Compilers Greg Morrisett.
ML Lists.1 Standard ML Lists. ML Lists.2 Lists  A list is a finite sequence of elements. [3,5,9] ["a", "list" ] []  ML lists are immutable.  Elements.
Cs776 (Prasad)L4Poly1 Polymorphic Type System. cs776 (Prasad)L4Poly2 Goals Allow expression of “for all types T” fun I x = x I : ’a -> ’a Allow expression.
ML Datatypes.1 Standard ML Data types. ML Datatypes.2 Concrete Datatypes  The datatype declaration creates new types  These are concrete data types,
Getting started with ML ML is a functional programming language. ML is statically typed: The types of literals, values, expressions and functions in a.
Functional Programming. Pure Functional Programming Computation is largely performed by applying functions to values. The value of an expression depends.
Overview of Previous Lesson(s) Over View  Front end analyzes a source program and creates an intermediate representation from which the back end generates.
ML: a quasi-functional language with strong typing Conventional syntax: - val x = 5; (*user input *) val x = 5: int (*system response*) - fun len lis =
Chapter ElevenModern Programming Languages1 A Fourth Look At ML.
A First Look at ML Chapter FiveModern Programming Languages, 2nd ed.1.
Patterns in ML functions. Formal vs. actual parameters Here's a function definition (in C): –int add (int x, int y) { return x + y; } –x and y are the.
CS 355 – PROGRAMMING LANGUAGES Dr. X. Apply-to-all A functional form that takes a single function as a parameter and yields a list of values obtained.
5/11/2015IT 3271 Types in ML (Ch 11) datatype bool = true | false; datatype 'element list = nil | :: of 'element * 'element list n Predefined, but not.
0 PROGRAMMING IN HASKELL Chapter 4 - Defining Functions.
ML: a quasi-functional language with strong typing Conventional syntax: - val x = 5; (*user input *) val x = 5: int (*system response*) - fun len lis =
Programming in the large in ML Need mechanisms for –Modularization –Information hiding –Parametrization of interfaces While retaining type inference Modules:
Introduction to ML - Part 2 Kenny Zhu. What is next? ML has a rich set of structured values Tuples: (17, true, “stuff”) Records: {name = “george”, age.
Introduction to ML Last time: Basics: integers, Booleans, tuples,... simple functions introduction to data types This time, we continue writing an evaluator.
Functional programming: LISP Originally developed for symbolic computing First interactive, interpreted language Dynamic typing: values have types, variables.
Type Checking  Legality checks  Operator determination  Overload resolution.
1 Functional Programming and ML. 2 What’s wrong with Imperative Languages? State State Introduces context sensitivity Introduces context sensitivity Harder.
SchemeCOP Introduction to Scheme. SchemeCOP Scheme Meta-language for coding interpreters –“ clean ” semantics Scheme = LISP + ALGOL –simple.
Introduction to ML A Quasi-Functional Language With Strong Typing And Type Inference.
ML Introduction.1 Standard ML Introduction. ML Introduction.2 Includes: Most of the examples Most of the questions Most of the answers... Recommended.
CS 2104 : Prog. Lang. Concepts. Functional Programming I Lecturer : Dr. Abhik Roychoudhury School of Computing From Dr. Khoo Siau Cheng’s lecture notes.
PrasadCS7761 Haskell Data Types/ADT/Modules Type/Class Hierarchy Lazy Functional Language.
ML Datatypes.1 Standard ML Data types. ML Datatypes.2 Concrete Datatypes  The datatype declaration creates new types  These are concrete data types,
0 REVIEW OF HASKELL A lightening tour in 45 minutes.
CSE-321 Programming Languages Introduction to Functional Programming (Part II) POSTECH March 13, 2006 박성우.
Patterns in OCaml functions. Formal vs. actual parameters Here's a function definition (in C): –int add (int x, int y) { return x + y; } –x and y are.
CSC 580 – Theory of Programming Languages, Spring, 2009 Week 9: Functional Languages ML and Haskell, Dr. Dale E. Parson.
Chapter 9: Functional Programming in a Typed Language.
Functional Programming With examples in F#. Pure Functional Programming Functional programming involves evaluating expressions rather than executing commands.
1-Nov-15 Haskell II Functions and patterns. Data Types Int + - * / ^ even odd Float + - * / ^ sin cos pi truncate Char ord chr isSpace isUpper … Bool.
Chapter Fifteen: Functional Programming Languages Lesson 12.
A Second Look At ML 1. Outline Patterns Local variable definitions A sorting example 2.
A Third Look At ML Chapter NineModern Programming Languages, 2nd ed.1.
CS 2104 – Prog. Lang. Concepts Functional Programming II Lecturer : Dr. Abhik Roychoudhury School of Computing From Dr. Khoo Siau Cheng’s lecture notes.
1 CS 457/557: Functional Languages Lists and Algebraic Datatypes Mark P Jones Portland State University.
Error Example - 65/4; ! Toplevel input: ! 65/4; ! ^^ ! Type clash: expression of type ! int ! cannot have type ! real.
Introduction to Objective Caml. General comments ML is a purely functional language--there are (almost) no side effects There are two basic dialects of.
Chapter SevenModern Programming Languages1 A Second Look At ML.
A FIRST LOOK AT ML Chapter Five Modern Programming Languages 1.
ML Lists.1 Standard ML Lists. ML Lists.2 Lists  A list is a finite sequence of elements. [3,5,9] ["a", "list" ] []  Elements may appear more than once.
1 FP Foundations, Scheme In Text: Chapter Chapter 14: FP Foundations, Scheme Mathematical Functions Def: A mathematical function is a mapping of.
Cs7120 (Prasad)L1-FP-HOF1 Functional Programming Basics Correctness > Clarity > Efficiency.
Cs776 (Prasad)L2HOF1 Higher-Order Functions. cs776 (Prasad)L2HOF2 Higher-Order Functions A function that takes a function as argument and/or returns a.
An introduction to functional programming using Haskell CENG242 –Recitation 1.
6-Jul-16 Haskell II Functions and patterns. Data Types Int + - * / ^ even odd Float + - * / ^ sin cos pi truncate Char ord chr isSpace isUpper … Bool.
Functional Programming
Type Checking and Type Inference
Principles of programming languages 12: Functional programming
ML: a quasi-functional language with strong typing
Introduction to Scheme
ML Again ( Chapter 7) Patterns Local variable definitions
A lightening tour in 45 minutes
Closures and Streams cs784(Prasad) L11Clos
Objective caml Daniel Jackson MIT Lab for Computer Science 6898: Advanced Topics in Software Design March 18, 2002.
FP Foundations, Scheme In Text: Chapter 14.
CSE 341 Section 5 Winter 2018.
CSCE 314: Programming Languages Dr. Dylan Shell
CSE-321 Programming Languages Introduction to Functional Programming
Assignments and Procs w/Params
Presentation transcript:

Introduction to ML A Quasi-Functional Language With Strong Typing And Type Inference

Example of Interactive Session Conventional syntax: Conventional syntax: val x = 5; (*user input *) val x = 5; (*user input *) > val x = 5: int (*system response*) > val x = 5: int (*system response*) fun len lis = if (null lis) then 0 else 1 + len (tl lis); fun len lis = if (null lis) then 0 else 1 + len (tl lis); > val len = fn : ‘a list -> int > val len = fn : ‘a list -> int Type inference for local entities Type inference for local entities x * x * x; x * x * x; > val it = 125: int (* it denotes last computation*) > val it = 125: int (* it denotes last computation*)

Operations on lists Similar to LISP, with (hd, tl, ::) instead of (car, cdr, cons) Similar to LISP, with (hd, tl, ::) instead of (car, cdr, cons) - fun append (x, y) = if null (x) then y - fun append (x, y) = if null (x) then y else hd (x) :: append (tl (x), y); else hd (x) :: append (tl (x), y); > val append = fn: ‘a list * ‘a list -> ‘a list > val append = fn: ‘a list * ‘a list -> ‘a list (* a function that takes a pair of lists and yields a list *) (* a function that takes a pair of lists and yields a list *) - fun upto (m, n) = - fun upto (m, n) = if m > n then [ ] else m :: upto (m+1, n); if m > n then [ ] else m :: upto (m+1, n); > val upto = fn : int * int -> int list > val upto = fn : int * int -> int list (* a function that takes two numbers and yields a list *) (* a function that takes two numbers and yields a list *)

Patterns A simple mechanism to describe and name parts of a structure fun prod [ ] = 1 (* if list is empty *) A simple mechanism to describe and name parts of a structure fun prod [ ] = 1 (* if list is empty *) | prod (n::ns) = n * prod (ns); (* n is first element *) | prod (n::ns) = n * prod (ns); (* n is first element *) A list can be described by its head and its tail A list can be described by its head and its tail fun maxl [m] : int = m fun maxl [m] : int = m | maxl (m::n::ns) if m > n then maxl (m ::ns) | maxl (m::n::ns) if m > n then maxl (m ::ns) else maxl (n :: ns) else maxl (n :: ns)

Recursion and iteration A function that returns the first i elements of a list: A function that returns the first i elements of a list: fun take ([ ], I) = [ ] fun take ([ ], I) = [ ] | take (x::xs, I) = if I > 0 then x::take (xs, I - 1) else [ ]; | take (x::xs, I) = if I > 0 then x::take (xs, I - 1) else [ ]; Non-recursive version: introduce an accumulator argument: Non-recursive version: introduce an accumulator argument: fun itake ([ ], _, taken) = taken (* _ is pattern for anything *) fun itake ([ ], _, taken) = taken (* _ is pattern for anything *) | itake (x::xs, I, taken) = | itake (x::xs, I, taken) = if I > 0 then itake (xs, I - 1, x::taken) if I > 0 then itake (xs, I - 1, x::taken) else taken; else taken; > var rtake = fn: ‘a list * int * ‘a list -> ‘a list > var rtake = fn: ‘a list * int * ‘a list -> ‘a list

A classic in functional form: quicksort fun quick [ ] = [ ] fun quick [ ] = [ ] | quick [x:real] = [x] | quick [x:real] = [x] | quick (a::bs) = | quick (a::bs) = let fun partition (left, right, [ ]) = let fun partition (left, right, [ ]) = (quick (quick right) (quick (quick right) | partition (left, right, x::xs) = | partition (left, right, x::xs) = if x <= a then partition (x::left, right, xs) if x <= a then partition (x::left, right, xs) else partition (left, x:: right, xs) else partition (left, x:: right, xs) in in partition ([a], [ ], bs) end; partition ([a], [ ], bs) end; > val quick : fn : real list -> real list;

A single formal is sufficient If function takes more than one argument, say that it takes a single composite one: If function takes more than one argument, say that it takes a single composite one: fun exp (x, n) = if n = 0 then 1 fun exp (x, n) = if n = 0 then 1 else x * exp (x, n-1); else x * exp (x, n-1); > val exp = fn : int * int -> int > val exp = fn : int * int -> int Single argument is a tuple (int, int) Single argument is a tuple (int, int) Can also define records with named components Can also define records with named components

The type system Primitive types: bool, int, char, real, string Primitive types: bool, int, char, real, string Constructors: list, array, product (record), function Constructors: list, array, product (record), function an expression has a corresponding type expression an expression has a corresponding type expression the interpreter builds the type expression for each input the interpreter builds the type expression for each input type checking requires that type expression of functions and their arguments match, and that type expression of context match result of function type checking requires that type expression of functions and their arguments match, and that type expression of context match result of function

Boolean Values Two values Two values true and false true and false The usual set of logical operators etc The usual set of logical operators etc

Integers (type int) Can notate in either decimal or hex (0xaa) Can notate in either decimal or hex (0xaa) Negative sign uses ~ Negative sign uses ~ This is because unary minus is an operator This is because unary minus is an operator But ~ is part of the number But ~ is part of the number Most languages don’t have negative literals Most languages don’t have negative literals Which is an odd corner Which is an odd corner All the usual arithmetic operators All the usual arithmetic operators

Unsigned (type word) A distinct type from int A distinct type from int Notated as 123w or 0wxff Notated as 123w or 0wxff Must be able to tell type of literal Must be able to tell type of literal From the literal itself From the literal itself Without any context Without any context Usual arithmetic operators Usual arithmetic operators (but not abs, unary minus) (but not abs, unary minus)

Floating-point Type (real) Notated with either a decimal point and a fractional part or an exponent or both Notated with either a decimal point and a fractional part or an exponent or both E4 3E4 Usual arithmetic operators Usual arithmetic operators Note that usual arithmetic operators are overloaded, but must be able to tell type! Note that usual arithmetic operators are overloaded, but must be able to tell type! No implicit conversions between numeric types, functions in library used instead. No implicit conversions between numeric types, functions in library used instead.

String Type String is a primitive String is a primitive Not a vector of characters Not a vector of characters Usual notation (like Ada or C) Usual notation (like Ada or C) Carret (^) is concatenation Carret (^) is concatenation There is also a type char for single chars There is also a type char for single chars Function str makes char into a string Function str makes char into a string Note everything is case sensitive Note everything is case sensitive All keywords lower case All keywords lower case

Example of Simple Arithmetic Zeller function for day of the week Zeller function for day of the week val floor = Real.floor val real = Real.fromInt val zc = fn (d, m, y, c) => (floor (2.61 * real (m) - 0.2) + d + y + y div 4 + c div * c) mod 7; val floor = Real.floor val real = Real.fromInt val zc = fn (d, m, y, c) => (floor (2.61 * real (m) - 0.2) + d + y + y div 4 + c div * c) mod 7; Note that the following are equivalent val zc = fn … fun zc … Note that the following are equivalent val zc = fn … fun zc …

Local Variables Zeller function rewritten (floor, real local) Zeller function rewritten (floor, real local) local val floor = Real.floor val real = Real.fromInt in val zc = fn (d, m, y, c) => (floor (2.61 * real (m) - 0.2) + d + y + y div 4 + c div * c) mod 7; end; local val floor = Real.floor val real = Real.fromInt in val zc = fn (d, m, y, c) => (floor (2.61 * real (m) - 0.2) + d + y + y div 4 + c div * c) mod 7; end;

Use of let Local allows decls used in other decls Local allows decls used in other decls Let allows decls used in expressions Let allows decls used in expressions (* Radix for non-negative nums *) val rec radix = fn (n, base) => let val b = size base val digit = fn n => str (String.sub (base, n)) val radix' = fn (true, n) = digit n | (false, n) => radix (n div b, base) ^ digit (n mod b) in radix' (n let val b = size base val digit = fn n => str (String.sub (base, n)) val radix' = fn (true, n) = digit n | (false, n) => radix (n div b, base) ^ digit (n mod b) in radix' (n < b, n) end;

Block structure and nesting Example of nesting: Example of nesting: fun findroot (a, x, acc) = fun findroot (a, x, acc) = (* standard Newton-Raphson *) (* standard Newton-Raphson *) let val nextx = (a / x +x) / 2.0 (*next approximation *) let val nextx = (a / x +x) / 2.0 (*next approximation *) in in if abs (x - nextx) < acc*x then nextx if abs (x - nextx) < acc*x then nextx else findroot (a, nextx, acc ) else findroot (a, nextx, acc ) end; end; (*tail recursion rather than iteration *) (*tail recursion rather than iteration *)

What is an ML Program So far we have seen functions and expressions, but what is an ML program? So far we have seen functions and expressions, but what is an ML program? Answer, a bunch of definitions and an expression to evaluate, typically: Answer, a bunch of definitions and an expression to evaluate, typically: let declarations in expression end; let declarations in expression end;

Functionals fun exists pred [ ] = false fun exists pred [ ] = false | exists pred (x::xs) = (pred x) orelse exists pred xs; | exists pred (x::xs) = (pred x) orelse exists pred xs; (* pred is a predicate : a function that delivers a boolean *) > val exists : fn : (‘a -> bool) -> ‘a list -> bool > val exists : fn : (‘a -> bool) -> ‘a list -> bool fun all pred [ ] = true fun all pred [ ] = true | all pred (x::xs) = (pred x) andalso all pred xs; > val all : fn : (‘a -> bool) -> ‘a list -> bool | all pred (x::xs) = (pred x) andalso all pred xs; > val all : fn : (‘a -> bool) -> ‘a list -> bool fun filter pred [ ] = [ ] fun filter pred [ ] = [ ] | filter (x::xs) = | filter (x::xs) = if pred x then x :: filter pred xs if pred x then x :: filter pred xs else filter pred xs; else filter pred xs; > val filter = fn : (‘a -> bool) -> ‘a list –> ‘a list > val filter = fn : (‘a -> bool) -> ‘a list –> ‘a list

Currying: partial bindings a b c means (a b) c: (a b) yields a function that is applied to c a b c means (a b) c: (a b) yields a function that is applied to c fun app2 x y = if null x then y fun app2 x y = if null x then y else (hd x) :: app2 (tl x) y; else (hd x) :: app2 (tl x) y; > val app2 = fn : ‘a list -> ‘a list -> a’list > val app2 = fn : ‘a list -> ‘a list -> a’list (*a function that given a list yields a function that takes a list and yields a list *) (*a function that given a list yields a function that takes a list and yields a list *) val ap123 = app2 [1, 2, 3]; val ap123 = app2 [1, 2, 3]; > val ap123 = fn : int list -> int list > val ap123 = fn : int list -> int list ap123 [10, 20, 30]; ap123 [10, 20, 30]; > val it = [1, 2, 3, 10, 20, 30] > val it = [1, 2, 3, 10, 20, 30]

Type inference fun incr x = x + 1; fun incr x = x + 1; > val incr = fn : int -> int > val incr = fn : int -> int because of its appearance in (x+1), x must be integer because of its appearance in (x+1), x must be integer fun add2 x = incr (incr x); fun add2 x = incr (incr x); > val add2 = fn : int -> int > val add2 = fn : int -> int incr returns an integer, so add2 does as well incr returns an integer, so add2 does as well x is argument of incr, so must be integer x is argument of incr, so must be integer val wrong = incr 7; val wrong = incr 7; > Error: operator and operand don’t agree > Error: operator and operand don’t agree

Polymorphism fun len x = if null x then 0 fun len x = if null x then 0 else 1 + len (tl x); else 1 + len (tl x); Works for any kind of list. What is its type expression? Works for any kind of list. What is its type expression? > val len : fn = ‘a list -> int > val len : fn = ‘a list -> int ‘a denotes a type variable. Implicit universal quantification: ‘a denotes a type variable. Implicit universal quantification: for any a, len applies to a list of a’s. for any a, len applies to a list of a’s. fun copy lis = if null lis then nil fun copy lis = if null lis then nil else hd (lis) :: copy (tl lis); else hd (lis) :: copy (tl lis);

Type inference and unification Type expressions are built by solving a set of equations Type expressions are built by solving a set of equations fun reduce f lis init = if null lis then init fun reduce f lis init = if null lis then init else f ((hd lis), reduce f (tl lis) init)) else f ((hd lis), reduce f (tl lis) init)) null : ‘a list -> bool null : ‘a list -> bool hd : ‘b list -> ‘b hd : ‘b list -> ‘b tl : ‘c list -> ‘c list tl : ‘c list -> ‘c list apply : (‘d -> e’) * ‘d -> ‘e (*function application*) apply : (‘d -> e’) * ‘d -> ‘e (*function application*) let b be the type of init. Let a be the element type of lis. let b be the type of init. Let a be the element type of lis. Then f takes an a and a b and returns a b. Then f takes an a and a b and returns a b. > val reduce = fn : (‘a -> ‘b -> ‘b) -> (‘a list) -> ‘b -> ‘b > val reduce = fn : (‘a -> ‘b -> ‘b) -> (‘a list) -> ‘b -> ‘b

Unification algorithm A type variable can be unified with another variable A type variable can be unified with another variable ‘a unifies with ‘b => ‘a and ‘b are the same ‘a unifies with ‘b => ‘a and ‘b are the same A type variable can be unified with a constant A type variable can be unified with a constant ‘a unifies with int => all occurences of ‘a mean int ‘a unifies with int => all occurences of ‘a mean int A type variable can be unified with an expression A type variable can be unified with an expression ‘a unifies with ‘b list ‘a unifies with ‘b list ‘a does not unify with ‘a list ‘a does not unify with ‘a list A constant can be unified with itself int is int A constant can be unified with itself int is int An expression can be unified with another expression if the constructors are identical and if the arguments can be unified (recursive): An expression can be unified with another expression if the constructors are identical and if the arguments can be unified (recursive): (int -> int) list unifies with ‘a list, ‘a is a function on integers (int -> int) list unifies with ‘a list, ‘a is a function on integers

Type system does not handle overloading well fun plus x y = x + y; fun plus x y = x + y; operator is overloaded, cannot be resolved from context (error in some versions, defaults to int in others) operator is overloaded, cannot be resolved from context (error in some versions, defaults to int in others) The type system can decide that a function takes ‘a but not that it takes an int or real The type system can decide that a function takes ‘a but not that it takes an int or real Can use explicit typing to select interpretation: Can use explicit typing to select interpretation: fun mix (x, y,z) = x * y + z:real; fun mix (x, y,z) = x * y + z:real; > mix : (real * real * real) -> real > mix : (real * real * real) -> real

Parametric polymorphism vs. generics A function whose type expression has type variables applies to an infinite set of types. A function whose type expression has type variables applies to an infinite set of types. Equality of type expressions means structural equivalence. Equality of type expressions means structural equivalence. All applications of a polymorphic function use the same body: no need to instantiate. All applications of a polymorphic function use the same body: no need to instantiate. let val ints = [1, 2, 3]; let val ints = [1, 2, 3]; val strs = [“this”, “that”]; val strs = [“this”, “that”]; in in len ints + len strs (* int list -> int, string list -> int *) len ints + len strs (* int list -> int, string list -> int *) end; end; > val it = 5: int > val it = 5: int

User-defined types and inference A user-defined type introduces constructors: A user-defined type introduces constructors: datatype tree = leaf of int | node of tree * tree datatype tree = leaf of int | node of tree * tree leaf and node are type constructors leaf and node are type constructors can define functions by pattern: can define functions by pattern: fun sum (leaf (t)) = t fun sum (leaf (t)) = t | sum (node (t1, t2)) = sum t1 + sum t2; | sum (node (t1, t2)) = sum t1 + sum t2; > val sum = fn : tree -> int > val sum = fn : tree -> int

Parameterized datatypes fun flatten (leaf (t)) = [t] fun flatten (leaf (t)) = [t] | flatten (node (t1, t2)) = flatten flatten (t2); | flatten (node (t1, t2)) = flatten flatten (t2); > flatten: tree -> int list > flatten: tree -> int list datatype ‘a gentree = leaf of ‘a datatype ‘a gentree = leaf of ‘a | node of ‘a gentree * ‘a gentree; | node of ‘a gentree * ‘a gentree; val names = node (leaf (“this”), leaf (“that”)); val names = node (leaf (“this”), leaf (“that”)); Here names is of type string gentree Here names is of type string gentree

Programming in the large in ML Need mechanisms for Need mechanisms for Modularization Modularization Information hiding Information hiding Parametrization of interfaces Parametrization of interfaces While retaining type inference While retaining type inference Modules: like packages / namespaces Modules: like packages / namespaces Signatures: like package specifications /Java interfaces Signatures: like package specifications /Java interfaces Functors: like generics with formal packages Functors: like generics with formal packages

Structures structure Complex = struct type t = real * real; type t = real * real; val zero = (0.0, 0.0):t; (*qualification may be needed *) val zero = (0.0, 0.0):t; (*qualification may be needed *) val i = (0.0, 1.0); val i = (0.0, 1.0); fun sum ((x, y), (x1, y1)) = (x+x1, y+y1):t; fun sum ((x, y), (x1, y1)) = (x+x1, y+y1):t; fun prod ((x, y), (x1, y1)) = (x*x1 – y*y1, x*y1 + y*x1):t; fun prod ((x, y), (x1, y1)) = (x*x1 – y*y1, x*y1 + y*x1):t; fun inv ((x, y)) = fun inv ((x, y)) = let val den = x*x + y+y let val den = x*x + y+y in in (x / den, ~ y / den): t (x / den, ~ y / den): t end; end; fun quo (z, z1) = prod (z, inv (z1)):t; fun quo (z, z1) = prod (z, inv (z1)):t; end;

Using a structure use (“complex.ml”); > signature Complex : Complex.prod (Complex.i, Complex.i); > val it = (~1.0, 0.0); > val it = (~1.0, 0.0); val pi4 = (0.707, 0.707); > val pi4 … real * real structural equivalence Complex.prod (pi4, pi4); > val it = … : Complex.t;

Signatures Interface description without implementation: Interface description without implementation: signature CMPLX = signature CMPLX = sig sig type t type t val zero : t val zero : t val i : t val i : t val sum : t * t -> t val sum : t * t -> t val diff : t * t -> t val diff : t * t -> t val prod : t * t -> t val prod : t * t -> t val inv : t -> t val inv : t -> t val quo : t * t -> t val quo : t * t -> t end end

Multiple implementations structure complex1 : CMPLX = struct type t = real*real; (* cartesian representation *) type t = real*real; (* cartesian representation *) val zero = (0.0, 0.0); val zero = (0.0, 0.0); val i = (0.0, 1.0); val i = (0.0, 1.0);… Structure ComplexPolar: CMPLX = Struct type t = real*real (*polar representation*) type t = real*real (*polar representation*) val zero = (0.0, 0.0); val zero = (0.0, 0.0); val pi = ; val pi = ; val i := (0.0, pi / 2.0); val i := (0.0, pi / 2.0);

Information Hiding Only signature should be visible Only signature should be visible Declare structure to be opaque: Declare structure to be opaque: structure polar :> CMPLX = …. structure polar :> CMPLX = …. (Structure can be opaque or transparent depending on context). (Structure can be opaque or transparent depending on context). Can export explicit constructors and equality for type. Otherwise, equivalent to limited private types in Ada. Can export explicit constructors and equality for type. Otherwise, equivalent to limited private types in Ada. Can declare as eqtype to export equality Can declare as eqtype to export equality

Functors Structures and signatures are not first-class objects. Structures and signatures are not first-class objects. A program (structure) can be parametrized by a signature A program (structure) can be parametrized by a signature functor testComplex (C : CMPLX) = functor testComplex (C : CMPLX) = struct struct open C; (*equivalent to use clause*) open C; (*equivalent to use clause*) fun FFT.. fun FFT.. end; end; structure testPolar = testComplex (Complexpolar); structure testPolar = testComplex (Complexpolar); (* equivalent to instantiation with a package *) (* equivalent to instantiation with a package *)

Imperative Programming in ML A real language needs operations with side effects, state, and variables A real language needs operations with side effects, state, and variables Need to retain type inference Need to retain type inference - val p = ref 5; - val p = ref 5; val p = ref 5 : int ref ; (* ref is a type constructor*) val p = ref 5 : int ref ; (* ref is a type constructor*) - !p * 2; (* dereference operation *) - !p * 2; (* dereference operation *) val it = 10: int; val it = 10: int; - p := !p * 3; - p := !p * 3; val it = ( ) : unit (* assignment has no value *) val it = ( ) : unit (* assignment has no value *) References are equality types (pointer equality)

The library Lists structure: useful Operations on Lists Lists structure: useful Operations on Lists Listpairs structure, operates on 2 lists,e.g. Listpairs structure, operates on 2 lists,e.g. ListPair.unzip : ('a * 'b) list -> 'a list * 'b list ListPair.zip : 'a list * 'b list -> ('a * 'b) list ListPair.unzip : ('a * 'b) list -> 'a list * 'b list ListPair.zip : 'a list * 'b list -> ('a * 'b) list Vector operations (allow indexing) Vector operations (allow indexing)

Lazy Evaluation Delay evaluation till value needed Delay evaluation till value needed Some languages do this by default (Haskel and Miranda are examples) Some languages do this by default (Haskel and Miranda are examples) Advantage is avoiding evaluating stuff that is never needed, and aids correctness Advantage is avoiding evaluating stuff that is never needed, and aids correctness fun take x y = y fun take x y = y Are the following equivalent? Are the following equivalent? expr1 expr1 Take expr2 expr1 Take expr2 expr1 No, because expr2 might not terminate No, because expr2 might not terminate ML is strict (but laziness can be simulated using functional forms that delay evaluation) ML is strict (but laziness can be simulated using functional forms that delay evaluation) There are forms that assist in this approach (e.g. delayed) There are forms that assist in this approach (e.g. delayed)

Abstract Data Types abstype 'a set = null | ins of 'a * 'a set with val emptyset = null val addset = ins fun memberset (x, null) = false | memberset (x, ins (v, s)) = x = v orelse memberset (x, s) local fun subset (null, _) = true | subset (ins (x, s1), s2) = memberset (x, s1) andalso subset (s1, s2) in fun equalset (s1, s2) = subset (s1, s2) andalso subset (s2, s1) end end; abstype 'a set = null | ins of 'a * 'a set with val emptyset = null val addset = ins fun memberset (x, null) = false | memberset (x, ins (v, s)) = x = v orelse memberset (x, s) local fun subset (null, _) = true | subset (ins (x, s1), s2) = memberset (x, s1) andalso subset (s1, s2) in fun equalset (s1, s2) = subset (s1, s2) andalso subset (s2, s1) end end;