- 229 Views
- Uploaded on

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

**An Image/Link below is provided (as is) to download presentation**

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

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
- 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)

Intro to ML

- 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

Preliminaries

- 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

Preliminaries

- 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

Basic Values

- ();

> () : 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

Basic Values

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

Using SML/NJ

- 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

Larger Projects

- 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

Compilation Manager

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

What is next?

- 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

An interpreterprint

- Interpreters are usually implemented as a series of transformers:

lexing/

parsing

evaluate

stream of

characters

abstract

syntax

abstract

value

stream of

characters

An interpreterprint

compilers

COS 320

US!

lexing/

parsing

evaluate

stream of

characters

abstract

syntax

abstract

value

stream of

characters

A little language (LL)

- 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)

LL abstract syntax in ML

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

LL abstract syntax in ML

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

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

If

Suc.

Bool

true

Zero

Suc.

Zero

Function declarations

function name

function parameter

fun isNumberValue t =

case t of

Zero => true

| Successor t2 => true

| _ => false

default pattern matches anything

What is the type of the parameter t? Of the function?

function name

function parameter

fun isNumberValue t =

case t of

Zero => true

| Successor t2 => true

| _ => false

default pattern matches anything

What is the type of the parameter t? Of the function?

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)

A type error

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

A type error

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

A very subtle error

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?

A very subtle error

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!)

Another function

fun isNumberValue t = ...

fun isValue t =

case t of

Bool _ => true

| t => isNumberValue t

Exceptions

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

Evaluator

fun isNumberValue t = ...

fun isValue t = ...

exception NoRule

fun eval1 t =

case t of

Bool _ | Zero => raise NoRule

...

Evaluator

...

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)

...

Evaluator

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

Finishing the Evaluator

fun eval1 t =

case t of

...

| ...

| Successor t => ...

| Predecessor t => ...

| IsZero t => ...

be sure your

case is

exhaustive

Finishing the Evaluator

fun eval1 t =

case t of

...

| ...

| Successor t => ...

What if we

forgot a case?

Finishing the Evaluator

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 => ...

Multi-step evaluation

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)

ML is all about functions

- 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 => ...)

Anonymous functions

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

Anonymous functions

a type definition (very convenient)

type ifun = int -> int

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

fun add3 x =

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

a pair of anonymous functions

Anonymous functions

type ifun = int -> int

val intCompose : ifun * ifun -> ifun =

fn (f,g) =>

(fn x => f (g x))

fun add3 x =

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

argument is pair of functions

pattern

match

against

arg

result is a function!

Another way to write a function

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

can be written as:

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

provided the function is not recursive;

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

Another way to write a function

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

Yet another way to write a function

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)

Parametric Polymorphism

- 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)

Parametric Polymorphism

- 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)

BAD!!

compose (fn x => x < 17) not

Parametric Polymorphism

- 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 ‘

Parametric Polymorphism

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

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

not : bool -> bool

Parametric Polymorphism

- compose (fn x => x) : ?

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

not : bool -> bool

Parametric Polymorphism

- compose (fn x => x) : ?

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

not : bool -> bool

‘d -> ‘d

Parametric Polymorphism

- 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

Parametric Polymorphism

- 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

Parametric Polymorphism

- compose (fn x => x) : ?

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

not : bool -> bool

‘d -> ‘d

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

Lists

- Lists:

nil : ‘a list

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

- 3 :: 4 :: 5 :: nil : int list
- (fn x => x) :: nil : (‘a -> ‘a) list

List Processing

- 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)

List Processing

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

List Processing

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.

ML Modules

- Signatures
- Interfaces
- Structures
- Implementations
- Functors
- Parameterized structures
- Functions from structures to structures

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

Structures

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))

Structures

structure Queue =

struct

...

end

structure Q = Queue

fun insert2 q x y =

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

convenient

abbreviation

Structures

structure Queue =

struct

...

end

open Queue

fun insert2 q x y =

insert (y, insert (q, x))

for lazy

programmers

-- not encouraged!

Structures

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

Signatures

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

Information hiding

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)

Signature Ascription

- 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

Other things

- 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...

Last Things

- 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

Download Presentation

Connecting to Server..