1 / 68

# Introduction to ML - PowerPoint PPT Presentation

Introduction to ML. You will be responsible for learning ML on your own. Today I will cover some basics Read Robert Harper’s notes on “an introduction to ML” See course webpage for pointers and info about how to get the software. Intro to ML. Highlights Functional Language

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

## PowerPoint Slideshow about 'Introduction to ML' - arleen

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

• You will be responsible for learning ML on your own.

• Today I will cover some basics

• Read Robert Harper’s notes on “an introduction to ML”

• See course webpage for pointers and info about how to get the software

• Highlights

• Functional Language

• Functions are pervasive:

• First-class values

• Storable, arguments, results, nested

• Strongly-typed language

• Every expression has a type

• Certain errors cannot occur

• Polymorphic types provide flexibility

• Flexible Module System

• Abstract Types

• Higher-order modules (functors)

• Interactive Language

• Type in expressions

• Evaluate and print type and result

• Compiler as well

• High-level programming features

• Data types

• Pattern matching

• Exceptions

• Mutable data discouraged

• Read – Eval – Print – Loop

- 3 + 2;

• Read – Eval – Print – Loop

- 3 + 2;

> 5: int

• Read – Eval – Print – Loop

- 3 + 2;

> 5: int

- it + 7;

> 12 : int

• Read – Eval – Print – Loop

- 3 + 2;

> 5: int

- it + 7;

> 12 : int

- it – 3;

> 9 : int

- 4 + true;

Type clash in : 3 + true

Looking for a : int Type

I have found a : bool Error

• Read – Eval – Print – Loop

- 3 + 2;

> 5: int

- it + 7;

> 12 : int

- it – 3;

> 9 : int

- 4 + true;

Type clash in : 3 + true

Looking for a : int Type

I have found a : bool Error

- 3 div 0;

Failure : Div - run-time error

- ();

> () : unit => like “void” in C (sort of)

=> the uninteresting value/type

- true;

> true : bool

- false;

> false : bool

- if it then 3+2 else 7; “else” clause is always necessary

> 7 : int

- false andalso loop_Forever;

> false : bool and also, or else short-circuit eval

Integers

- 3 + 2

> 5 : int

- 3 + (if not true then 5 else 7);

> 10 : int No division between expressions

and statements

Strings

- “Dave” ^ “ “ ^ “Walker”;

> “Dave Walker” : string

- print “foo\n”;

foo

> 3 : int

Reals

- 3.14;

> 3.14 : real

• Interactive mode is a good way to start learning and to debug programs, but…

• Type in a series of declarations into a “.sml” file

- use “foo.sml”

[opening foo.sml]

list of declarations

with their types

• SML has its own built in interactive “make”

• Pros:

• It automatically does the dependency analysis for you

• No crazy makefile syntax to learn

• Cons:

• May be more difficult to interact with other languages or tools

sources.cm

a.sig

b.sml

c.sml

Group is

a.sig

b.sml

c.sml

• % sml

• OS.FileSys.chDir “~/courses/510/a2”;

• CM.make(); looks for “sources.cm”, analyzes dependencies

• [compiling…] compiles files in group

• [wrote…] saves binaries in ./CM/

• - CM.make’“myproj/”(); specify directory

• ML has a rich set of structured values

• Tuples: (17, true, “stuff”)

• Records: {name = “Dave”, ssn = 332177}

• Lists: 3::4::5::nil or [3,4]@[5]

• Datatypes

• Functions

• And more!

• Rather than list all the details, we will write a couple of programs

• Interpreters are usually implemented as a series of transformers:

lexing/

parsing

evaluate

print

stream of

characters

abstract

syntax

abstract

value

stream of

characters

compilers

COS 320

US!

lexing/

parsing

evaluate

print

stream of

characters

abstract

syntax

abstract

value

stream of

characters

• An arithmetic expression e is

• a boolean value

• an if statement (if e1 then e2 else e3)

• the number zero

• the successor of a number

• the predecessor of a number

• a test for zero (isZero e)

datatype term =

Bool of bool

| If of term * term * term

| Zero

| Successor of term

| Predecessor of term

| IsZero of term

-- constructors

are capitalized

-- constructors

can take a single

argument of a

particular type

type of a tuple

another eg: string * char

vertical bar

separates alternatives

If (Bool true, Zero, Successor (Successor Zero))

represents “if true then 0 else succ(succ 0)”

If

Suc.

Bool

true

Zero

Suc.

Zero

function name

function parameter

fun isNumberValue t =

case t of

Zero => true

| Successor t2 => true

| _ => false

default pattern matches anything

function name

function parameter

fun isNumberValue t =

case t of

Zero => true

| Successor t2 => true

| _ => false

default pattern matches anything

fun isNumberValue (t:term) : bool =

case t of

Zero => true

| Successor t2 => true

| _ => false

val isNumberValue : term -> bool

ML does type inference => you need not

annotate functions yourself (but it can be helpful)

fun isNumberValue t =

case t of

Zero => 0

| Successor t2 => true

| _ => false

line 22

line 25

ex.sml:22.3-25.15 Error: types of rules don't agree [literal]

earlier rule(s): term -> int

this rule: term -> bool

in rule:

Successor t2 => true

Actually, ML will give you several errors in a row:

ex.sml:22.3-25.15 Error: types of rules don't agree [literal]

earlier rule(s): term -> int

this rule: term -> bool

in rule:

Successor t2 => true

ex.sml:22.3-25.15 Error: types of rules don't agree [literal]

earlier rule(s): term -> int

this rule: term -> bool

in rule:

_ => false

fun isNumberValue t =

case t of

zero => true

| Successor t2 => true

| _ => false

The code above type checks. But when

we test it refined the function always returns “true.”

What has gone wrong?

fun isNumberValue t =

case t of

zero => true

| Successor t2 => true

| _ => false

The code above type checks. But when

we test it refined the function always returns “true.”

What has gone wrong?

-- zero is not capitalized

-- ML treats it like a variable pattern (matches anything!)

fun isNumberValue t = ...

fun isValue t =

case t of

Bool _ => true

| t => isNumberValue t

exception Error of string

fun debug s : unit = raise (Error s)

exception Error of string

fun debug s : unit = raise (Error s)

in SML interpreter:

- debug "hello";

uncaught exception Error

raised at: ex.sml:15.28-15.35

fun isNumberValue t = ...

fun isValue t = ...

exception NoRule

fun eval1 t =

case t of

Bool _ | Zero => raise NoRule

...

...

fun eval1 t =

case t of

Bool _ | Zero => raise NoRule

| If(Bool b,t2,t3) => (if b then t2 else t3)

| If(t1,t2,t3) => If (eval1 t1,t2,t3)

...

exception NoRule

fun eval1 t =

case t of

Bool _ | Zero => ...

| ...

| Successor t =>

if isValue t then

raise NoRule

else

let val t’ = eval1 t in

Successor t’

end

fun eval1 t =

case t of

...

| ...

| Successor t => ...

| Predecessor t => ...

| IsZero t => ...

be sure your

case is

exhaustive

fun eval1 t =

case t of

...

| ...

| Successor t => ...

What if we

forgot a case?

fun eval1 t =

case t of

...

| ...

| Successor t => ...

What if we

forgot a case?

ex.sml:25.2-35.12 Warning: match nonexhaustive

(Bool _ | Zero) => ...

If (Bool b,t2,t3) => ...

If (t1,t2,t3) => ...

Successor t => ...

fun eval1 t = ...

fun eval t =

let

fun loop t = loop (eval1 t)

val message = “Done\n”

in

((loop t) handle

NoRule => print message

| Error s => print s)

end

Be very

careful

with the

syntax of

handle

(use extra

parens)

• There are many different ways to define functions!

• I almost always use “fun f x = ...”

• When I am only going to use a function once and it is not recursive, I write an anonymous function:

• (fn x => ...)

binds a variable (n)

to a value (3)

val n = 3

val isNumberValue =

(fn t =>

case t of

zero => true

| Successor t2 => true

| _ => false)

binds a variable

(isNumberValue)

to the anonymous

function value

fn keyword

introduces

anonymous

fun

a type definition (very convenient)

type ifun = int -> int

val intCompose : ifun * ifun -> ifun = ...

intCompose ((fn x => x + 2), (fn y => y + 1)) x

a pair of anonymous functions

type ifun = int -> int

val intCompose : ifun * ifun -> ifun =

fn (f,g) =>

(fn x => f (g x))

intCompose ((fn x => x + 2), (fn y => y + 1)) x

argument is pair of functions

pattern

match

against

arg

result is a function!

fun f x = ........

can be written as:

val f = (fn x => ......)

provided the function is not recursive;

f does not appear in ........

fun f x = ....

can always be written as:

val rec f = (fn x => ...f can be used here...)

keyword rec declares a recursive function value

fun isNumberValue Zero = true

| isNumberValue (Successor t2) = true

| isNumberValue (_) = true

This is just an abbreviation for

fun isNumberValue t =

case t of

Zero => true

| Successor t2 => true

| _ => true

Yet another way to create a type error

fun isNumberValue 0 = true

| isNumberValue (Successor t2) = true

| isNumberValue (_) = true

ex.sml:9.1-11.29 Error: parameter or result constraints of

clauses don't agree [literal]

this clause: term -> 'Z

previous clauses: int -> 'Z

in declaration:

isNumberValue =

(fn 0 => true

| Successor t2 => true

| _ => true)

• Functions like compose work on objects of many different types

val compose =

fn f =>

fn g =>

fn x => f (g x)

compose (fn x => x + 1) (fn x => x + 2)

compose not (fn x => x < 17)

• Functions like compose work on objects of many different types

val compose =

fn f =>

fn g =>

fn x => f (g x)

compose not (fn x => x < 17)

compose (fn x => x < 17) not

• Functions like compose work on objects of many different types

val compose =

fn f =>

fn g =>

fn x => f (g x)

compose: (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)

Note: type variables are written with ‘

• compose not : (‘c -> bool) -> (c’ -> bool)

• compose not not : bool -> bool

compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)

not : bool -> bool

• compose (fn x => x) : ?

compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)

not : bool -> bool

• compose (fn x => x) : ?

compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)

not : bool -> bool

‘d -> ‘d

• compose (fn x => x) : ?

compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)

not : bool -> bool

must be

the same

ie:

‘a = ‘d

‘b = ‘d

‘d -> ‘d

• compose (fn x => x) : ?

compose : (‘d -> ‘d) -> (‘c -> ‘d) -> (‘c -> ‘d)

not : bool -> bool

must be

the same

ie:

‘a = ‘d

‘b = ‘d

‘d -> ‘d

• compose (fn x => x) : ?

compose : (‘d -> ‘d) -> (‘c -> ‘d) -> (‘c -> ‘d)

not : bool -> bool

‘d -> ‘d

(‘c -> ‘d) -> (‘c -> ‘d)

• Lists:

nil : ‘a list

:: : ‘a * ‘a list -> ‘a list

• 3 :: 4 :: 5 :: nil : int list

• (fn x => x) :: nil : (‘a -> ‘a) list

• Functions over lists are usually defined by case analysis (induction) over the structure of a list

• Hint: often, the structure of a function is

guided by the type of the argument (recall eval)

fun length l =

case l of

nil => 0

l x :: l => 1 + (length l)

fun map f l =

case l of

nil => []

l x :: l => (f x) :: (map f l)

an incredibly useful function:

- map (fn x => x+1) [1,2,3];

> val it = [2,3,4] ; int list

fun fold f a l =

case l of

nil => a

l x :: l => f (fold f a l) x

another incredibly useful function

what does it do?

use it to write map.

• Signatures

• Interfaces

• Structures

• Implementations

• Functors

• Parameterized structures

• Functions from structures to structures

• structure Queue =

struct

type ‘a queue = ‘a list * ‘a list

exception Empty

val empty = (nil, nil)

fun insert (x, q) = …

fun remove q = …

end

structure Queue =

struct

type ‘a queue = ‘a list * ‘a list

exception Empty

...

end

fun insert2 q x y =

Queue.insert (y, Queue.insert (q, x))

structure Queue =

struct

...

end

structure Q = Queue

fun insert2 q x y =

Q.insert (y, Q.insert (q, x))

convenient

abbreviation

structure Queue =

struct

...

end

open Queue

fun insert2 q x y =

insert (y, insert (q, x))

for lazy

programmers

-- not encouraged!

structure Queue =

struct

type ‘a queue = ‘a list * ‘a list

...

end

fun insert2 (q1,q2) x y : ‘a queue =

(x::y::q1,q2)

by default,

all components

of the structure

may be used

-- we know the

type ‘a queue

abstract type

-- we don’t know the

type ‘a queue

signature QUEUE =

sig

type ‘a queue

exception Empty

val empty : ‘a queue

val insert : ‘a * ‘a queue -> ‘a queue

val remove : ‘a queue -> ‘a * ‘a queue

end

signature QUEUE =

sig

type ‘a queue

...

end

structure Queue :> QUEUE =

struct

type ‘a queue = ‘a list * ‘a list

val empty = (nil, nil)

end

does not

type check

fun insert2 (q1,q2) x y : ‘a queue =

(x::y::q1,q2)

• Opaque ascription

• Provides abstract types

structure Queue :> QUEUE = …

• Transparent ascription

• A special case of opaque ascription

• Hides fields but does not make types abstract

structure Queue_E : QUEUE = …

• SEE Harper, chapters 18-22 for more on modules

• functors (functions from structures to structures)

• references (mutable data structures)

• ref e; !e; e1 := e2

• while loops, for loops

• arrays

• (* comments (* can be *) nested *)

• a bunch of other stuff...

• Learning to program in SML can be tricky at first

• But once you get used to it, you will never want to go back to imperative languages

• Check out the reference materials listed on the course homepage