• Aucun résultat trouvé

The practice of Mezzo

N/A
N/A
Protected

Academic year: 2022

Partager "The practice of Mezzo"

Copied!
160
0
0

Texte intégral

(1)

INRIA

IHP, April 2014

1 / 83

(2)

Jonathan Protzenko, Thibaut Balabonski, Henri Chataing, Armaël Guéneau, Cyprien Mangin.

2 / 83

(3)

Two lectures on Mezzo.

April 29th, 2pm: motivation and examples.

April 30th, 4pm: type soundness, data race freedom.

3 / 83

(4)

Write-once references: usage Mezzo: design principles Mezzo: motivation

Write-once references: interface & implementation

Algebraic data structures Sharing mutable data Conclusion

4 / 83

(5)

Write-once references: usage

5 / 83

(6)

A write-once reference:

can be writtenat mostonce;

can be read onlyafterit has been written.

Let us look at a concrete example of use...

6 / 83

(7)

Usage

.

frozen

get

.

open woref

val () = set (r1, 3);

(* r1 @ frozen int * r2 = r1 *) val x2 = get r2

(* r1 @ frozen int * r2 = r1 * x2 @ int *) val rs = (r1, r2)

(* r1 @ frozen int * r2 = r1 * x2 @ int

* rs @ (=r1, =r2) *)

(* rs @ (frozen int, frozen int) *)

. .

7 / 83

(8)

Usage

. writable...

new

get

.

open woref

val r1 = new () (* r1 @ writable *)

(* r1 @ frozen int * r2 = r1 *) val x2 = get r2

(* r1 @ frozen int * r2 = r1 * x2 @ int *) val rs = (r1, r2)

(* r1 @ frozen int * r2 = r1 * x2 @ int

* rs @ (=r1, =r2) *)

(* rs @ (frozen int, frozen int) *)

. .

7 / 83

(9)

Usage

. writable...

new

get

.

open woref

val r1 = new () (* r1 @ writable *) val r2 = r1

(* r1 @ writable * r2 = r1 *)

(* r1 @ frozen int * r2 = r1 *) val x2 = get r2

(* r1 @ frozen int * r2 = r1 * x2 @ int *) val rs = (r1, r2)

(* r1 @ frozen int * r2 = r1 * x2 @ int

* rs @ (=r1, =r2) *)

(* rs @ (frozen int, frozen int) *)

. .

7 / 83

(10)

Usage

. writable...

new

.

frozen .

set

get

.

open woref

val r1 = new () (* r1 @ writable *) val r2 = r1

(* r1 @ writable * r2 = r1 *) val () = set (r1, 3);

(* r1 @ frozen int * r2 = r1 *)

val x2 = get r2

(* r1 @ frozen int * r2 = r1 * x2 @ int *) val rs = (r1, r2)

(* r1 @ frozen int * r2 = r1 * x2 @ int

* rs @ (=r1, =r2) *)

(* rs @ (frozen int, frozen int) *)

. .

7 / 83

(11)

Usage

. writable...

new

.

frozen .

set

.

get

.

open woref

val r1 = new () (* r1 @ writable *) val r2 = r1

(* r1 @ writable * r2 = r1 *) val () = set (r1, 3);

(* r1 @ frozen int * r2 = r1 *) val x2 = get r2

(* r1 @ frozen int * r2 = r1 * x2 @ int *)

val rs = (r1, r2)

(* r1 @ frozen int * r2 = r1 * x2 @ int

* rs @ (=r1, =r2) *)

(* rs @ (frozen int, frozen int) *)

. .

7 / 83

(12)

Usage

. writable...

new

.

frozen .

set

.

get

.

open woref

val r1 = new () (* r1 @ writable *) val r2 = r1

(* r1 @ writable * r2 = r1 *) val () = set (r1, 3);

(* r1 @ frozen int * r2 = r1 *) val x2 = get r2

(* r1 @ frozen int * r2 = r1 * x2 @ int *) val rs = (r1, r2)

(* r1 @ frozen int * r2 = r1 * x2 @ int

* rs @ (=r1, =r2) *)

(* rs @ (frozen int, frozen int) *)

. .

7 / 83

(13)

Usage

. writable...

new

.

frozen .

set

.

get

.

open woref

val r1 = new () (* r1 @ writable *) val r2 = r1

(* r1 @ writable * r2 = r1 *) val () = set (r1, 3);

(* r1 @ frozen int * r2 = r1 *) val x2 = get r2

(* r1 @ frozen int * r2 = r1 * x2 @ int *) val rs = (r1, r2)

(* r1 @ frozen int * r2 = r1 * x2 @ int

* rs @ (=r1, =r2) *)

(* rs @ (frozen int, frozen int) *)

. .

7 / 83

(14)

. writable....

frozen .

set

.

get

. val r1 = new ()

(* r1 @ writable *) val r2 = r1

(* r1 @ writable * r2 = r1 *) val () = set (r1, 3);

(* r1 @ frozen int * r2 = r1 *) val x2 = get r2

(* r1 @ frozen int * r2 = r1 * x2 @ int *) val rs = (r1, r2)

(* r1 @ frozen int * r2 = r1 * x2 @ int

* rs @ (=r1, =r2) *)

(* rs @ (frozen int, frozen int) *)

. .

Demo!

7 / 83

(15)

Mezzo: design principles

8 / 83

(16)

Like a program logic, the static discipline isflow-sensitive.

Acurrent(set of)permission(s) existsat each program point.

Differentpermissions exist at different points.

Permissions do not exist at runtime.

9 / 83

(17)

Thus, there is no such thing asthetype of a variablex. Instead,

at each program pointin the scope ofx,

there may bezero, one, or morepermissions to usex

in certain ways.

10 / 83

(18)

Permissions havelayoutandownershipreadings.

e.g.,r @ writable

x @ tdescribes theshape and extentof a heap fragment, rooted atx, and describes certainaccess rightsfor it.

“To know aboutx” is “to have access tox” is “to ownx”.

11 / 83

(19)

Every permission is either duplicable or affine.

At first,

Immutabledata isduplicable, i.e., shareable.

Mutabledata isaffine, i.e., uniquely owned.

Mutable data can become immutable; not the converse.

12 / 83

(20)

Writinglet x = y in ... gives rise to an equationx = y.

It is a permission: x @ =y, where=yis asingleton type.

In its presence,x @ tandy @ tare interconvertible.

Thus,any name is as good as any other.

The same idea applies tolet x = xs.head in ....

13 / 83

(21)

A value can be copied (always). No permission is required.

(* empty *)

let y = (x, x) in (* y @ (=x, =x) *)

14 / 83

(22)

Value ̸ = permission

A duplicable permissioncanbe copied. This is implicit.

(* x @ int *) let y = (x, x) in

(* x @ int * y @ (=x, =x) *)

15 / 83

(23)

A duplicable permissioncanbe copied. This is implicit.

(* x @ int *) let y = (x, x) in

(* x @ int * y @ (=x, =x) *) (* x @ int * y @ (int, int) *)

15 / 83

(24)

Value ̸ = permission

An affine permissioncannotbe copied.

(* x @ ref int *) let y = (x, x) in

(* x @ ref int * y @ (=x, =x) *)

16 / 83

(25)

An affine permissioncannotbe copied.

(* x @ ref int *) let y = (x, x) in

(* x @ ref int * y @ (=x, =x) *)

assert y @ (ref int, ref int) (* WRONG! *)

In other words, mutable data cannot be shared.

16 / 83

(26)

x @ list intis duplicable: read access can be shared.

x = yis duplicable: equalities are forever.

x @ mlist intandx @ list (ref int)are affine: they give exclusive access to part of the heap.

17 / 83

(27)

x @ ref int * y @ ref intimpliesxandyare distinct.

Conjunction isseparatingat mutable data.

z @ (t, u)meansz @ (=x, =y) * x @ t * y @ u, forx,yfresh.

Hence, product is separating.

18 / 83

(28)

The same principle applies to records.

Hence,list (ref int)denotes a list ofdistinctreferences.

Mutable data must betree-structured.

thoughx @ ref (=x)can be written and constructed.

19 / 83

(29)

Mezzo: motivation

20 / 83

(30)

The types of OCaml, Haskell, Java, C#, etc.:

describe thestructureof data,

but do not distinguishtreesandgraphs,

and do not control who haspermissionto read or write.

21 / 83

(31)

Could a more ambitious static discipline:

rule outmore programming errors,

andenablenew programming idioms,

while remaining reasonablysimpleandflexible?

22 / 83

(32)

The uniqueness of read/write permissions:

rules out, or helps rule out, several categories of errors:

data races;

representation exposure;

violations of object protocols.

allowsthe type of an object to vary with time, which enables:

explicit memory re-use;

gradual initialization;

the description of object protocols.

23 / 83

(33)

This discipline is restrictive.

Fortunately,

there isno restrictionon the use of immutable data;

there areseveral waysof sharing mutable data:

(static) nesting & regions;

(dynamic) adoption & abandon;

(dynamic) locks.

24 / 83

(34)

A few desirable idioms become clumsy or downright impossible.

e.g., temporarily borrowing anaffineelement from a container (an array; a region; a user-defined data structure; …).

Work-arounds: see previous slide.

25 / 83

(35)

Write-once references: interface & implementation

26 / 83

(36)

A usage protocol can be described in a module signature:

Astateis a (user-defined) type.

Atransitionis a (user-defined) function.

27 / 83

(37)

This protocol has two states and four transitions.

abstract writable ..

abstract frozen a ..

fact duplicable (frozen a) ..

val new: () -> writable ..

val set: [a] (consumes r:..writable,.. x: a | duplicable..a)

-> (| r @ frozen a) ..

val get: [a] frozen a -> a ..

.

28 / 83

(38)

This protocol has two states and four transitions.

abstract writable ..

abstract frozen a ..

fact duplicable (frozen a) ..

val new: () -> writable ..

val set: [a] (consumes r:..writable,.. x: a | duplicable..a)

-> (| r @ frozen a) ..

val get: [a] frozen a -> a ..

. .

a state

28 / 83

(39)

This protocol has two states and four transitions.

abstract writable ..

abstract frozen a ..

fact duplicable (frozen a) ..

val new: () -> writable ..

val set: [a] (consumes r:..writable,.. x: a | duplicable..a)

-> (| r @ frozen a) ..

val get: [a] frozen a -> a ..

. .

another state

28 / 83

(40)

This protocol has two states and four transitions.

abstract writable ..

abstract frozen a ..

fact duplicable (frozen a) ..

val new: () -> writable ..

val set: [a] (consumes r:..writable,.. x: a | duplicable..a)

-> (| r @ frozen a) ..

val get: [a] frozen a -> a ..

. .

implicit transition from frozen to frozen * frozen

28 / 83

(41)

This protocol has two states and four transitions.

abstract writable ..

abstract frozen a ..

fact duplicable (frozen a) ..

val new: () -> writable ..

val set: [a] (consumes r:..writable,.. x: a | duplicable..a)

-> (| r @ frozen a) ..

val get: [a] frozen a -> a ..

. .

explicit transition into writable

28 / 83

(42)

This protocol has two states and four transitions.

abstract writable ..

abstract frozen a ..

fact duplicable (frozen a) ..

val new: () -> writable ..

val set: [a] (consumes r:..writable,.. x: a | duplicable..a)

-> (| r @ frozen a) ..

val get: [a] frozen a -> a ..

. .

set requires r (dynamic) and r @ writable (static)

28 / 83

(43)

This protocol has two states and four transitions.

abstract writable ..

abstract frozen a ..

fact duplicable (frozen a) ..

val new: () -> writable ..

val set: [a] (consumes r:..writable,.. x: a | duplicable..a)

-> (| r @ frozen a) ..

val get: [a] frozen a -> a ..

. .

consumes keyword means r @ writable NOT returned

28 / 83

(44)

This protocol has two states and four transitions.

abstract writable ..

abstract frozen a ..

fact duplicable (frozen a) ..

val new: () -> writable ..

val set: [a] (consumes r:..writable,.. x: a | duplicable..a)

-> (| r @ frozen a) ..

val get: [a] frozen a -> a ..

. .

duplicable a is a permission

28 / 83

(45)

This protocol has two states and four transitions.

abstract writable ..

abstract frozen a ..

fact duplicable (frozen a) ..

val new: () -> writable ..

val set: [a] (consumes r:..writable,.. x: a | duplicable..a)

-> (| r @ frozen a) ..

val get: [a] frozen a -> a ..

. .

explicit transition from writable to frozen

28 / 83

(46)

This protocol has two states and four transitions.

abstract writable ..

abstract frozen a ..

fact duplicable (frozen a) ..

val new: () -> writable ..

val set: [a] (consumes r:..writable,.. x: a | duplicable..a)

-> (| r @ frozen a) ..

val get: [a] frozen a -> a ..

. .

get r requires r @ frozen a

28 / 83

(47)

Writable { contents: () } data frozen a =

Frozen { contents:..(a | duplicable a) }

val new () : writable = Writable { contents = () }

val set [a] (consumes r: writable, x: a | duplicable a) : (| r @ frozen a) =

..r.contents <- x; ..

tag of r <- Frozen (* this is a no-op *)..

val get [a] (r: frozen a) : a = r.contents

.

29 / 83

(48)

Writable { contents: () } data frozen a =

Frozen { contents:..(a | duplicable a) }

val new () : writable = Writable { contents = () }

val set [a] (consumes r: writable, x: a | duplicable a) : (| r @ frozen a) =

..r.contents <- x; ..

tag of r <- Frozen (* this is a no-op *)..

val get [a] (r: frozen a) : a = r.contents

. .

29 / 83

(49)

Writable { contents: () } data frozen a =

Frozen { contents:..(a | duplicable a) }

val new () : writable = Writable { contents = () }

val set [a] (consumes r: writable, x: a | duplicable a) : (| r @ frozen a) =

..r.contents <- x; ..

tag of r <- Frozen (* this is a no-op *)..

val get [a] (r: frozen a) : a = r.contents

. .

29 / 83

(50)

Writable { contents: () } data frozen a =

Frozen { contents:..(a | duplicable a) }

val new () : writable = Writable { contents = () }

val set [a] (consumes r: writable, x: a | duplicable a) : (| r @ frozen a) =

..r.contents <- x; ..

tag of r <- Frozen (* this is a no-op *)..

val get [a] (r: frozen a) : a = r.contents

. .

29 / 83

(51)

Writable { contents: () } data frozen a =

Frozen { contents:..(a | duplicable a) }

val new () : writable = Writable { contents = () }

val set [a] (consumes r: writable, x: a | duplicable a) : (| r @ frozen a) =

..r.contents <- x; ..

tag of r <- Frozen (* this is a no-op *)..

val get [a] (r: frozen a) : a = r.contents

. .

29 / 83

(52)

Writable { contents: () } data frozen a =

Frozen { contents:..(a | duplicable a) }

val new () : writable = Writable { contents = () }

val set [a] (consumes r: writable, x: a | duplicable a) : (| r @ frozen a) =

..r.contents <- x; ..

tag of r <- Frozen (* this is a no-op *)..

val get [a] (r: frozen a) : a = r.contents

. .

29 / 83

(53)

Writable { contents: () } data frozen a =

Frozen { contents:..(a | duplicable a) }

val new () : writable = Writable { contents = () }

val set [a] (consumes r: writable, x: a | duplicable a) : (| r @ frozen a) =

..r.contents <- x; ..

tag of r <- Frozen (* this is a no-op *)..

val get [a] (r: frozen a) : a = r.contents

. .

29 / 83

(54)

Writable { contents: () } data frozen a =

Frozen { contents:..(a | duplicable a) }

val new () : writable = Writable { contents = () }

val set [a] (consumes r: writable, x: a | duplicable a) : (| r @ frozen a) =

..r.contents <- x; ..

tag of r <- Frozen (* this is a no-op *)..

val get [a] (r: frozen a) : a = r.contents

. .

29 / 83

(55)

Writable { contents: () } data frozen a =

Frozen { contents:..(a | duplicable a) }

val new () : writable = Writable { contents = () }

val set [a] (consumes r: writable, x: a | duplicable a) : (| r @ frozen a) =

..r.contents <- x; ..

tag of r <- Frozen (* this is a no-op *)..

val get [a] (r: frozen a) : a = r.contents

. .

29 / 83

(56)

Algebraic data structures Principles

Computing the length of a list Melding mutable lists

Concatenating immutable lists

Sharing mutable data Conclusion

30 / 83

(57)

Principles

31 / 83

(58)

The algebraic data type of immutable lists is defined as in ML:

data list a =

| Nil

| Cons { head: a; tail: list a }

32 / 83

(59)

To define a type of mutable lists, one adds a keyword:

data mutable mlist a =

| MNil

| MCons { head: a; tail: mlist a }

33 / 83

(60)

For instance,

x @ list intprovides (read) access to an immutable list of integers, rooted atx.

x @ mlist intprovides (exclusive, read/write) access to a mutable list of integers atx.

x @ list (ref int)offers read access to the spine and read/write access to the elements, which are distinct cells.

34 / 83

(61)

match xs with

| MNil ->

..

...

| MCons ->

..

let x = xs.head in

..

...

end

In contrast, traditional separation logic hasuntaggedunion.

.

35 / 83

(62)

match xs with

| MNil ->

..

...

| MCons ->

..

let x = xs.head in

..

...

end

In contrast, traditional separation logic hasuntaggedunion.

. .

xs @ mlist a

35 / 83

(63)

match xs with

| MNil ->

..

...

| MCons ->

..

let x = xs.head in

..

...

end

In contrast, traditional separation logic hasuntaggedunion.

. .

xs @ MNil

35 / 83

(64)

match xs with

| MNil ->

..

...

| MCons ->

..

let x = xs.head in

..

...

end

In contrast, traditional separation logic hasuntaggedunion.

. .

xs @ MCons { head: a; tail: mlist a }

35 / 83

(65)

match xs with

| MNil ->

..

...

| MCons ->

..

let x = xs.head in

..

...

end

In contrast, traditional separation logic hasuntaggedunion.

. .

xs @ MCons { head: (=h); tail: (=t) }

* h @ a

* t @ mlist a

35 / 83

(66)

match xs with

| MNil ->

..

...

| MCons ->

..

let x = xs.head in

..

...

end

In contrast, traditional separation logic hasuntaggedunion.

. .

xs @ MCons { head = h; tail = t }

* h @ a

* t @ mlist a

35 / 83

(67)

match xs with

| MNil ->

..

...

| MCons ->

..

let x = xs.head in

..

...

end

In contrast, traditional separation logic hasuntaggedunion.

. .

xs @ MCons { head = h; tail = t }

* h @ a

* t @ mlist a

* x = h

35 / 83

(68)

This illustrates two mechanisms:

A nominal permission can beunfoldedandrefined, yielding a structural permission.

A structural permission can bedecomposed,

yielding separate permissions for the block and its fields.

These reasoning steps are implicit and reversible.

36 / 83

(69)

Computing the length of a list

37 / 83

(70)

Here is the type of thelengthfunction for mutable lists.

val length: [a] mlist a -> int

It should be understood as follows:

lengthrequires one argumentxs,

along with the permissionxs @ mlist a.

lengthreturns one resultn,

along with the permissionxs @ mlist a * n @ int.

38 / 83

(71)

match xs with..

| MNil ->..

accu..

| MCons ->..

length_aux (accu + 1, xs.tail)..

end

val length [a] (xs: mlist a) : int = length_aux (0, xs)

.

39 / 83

(72)

match xs with..

| MNil ->..

accu..

| MCons ->..

length_aux (accu + 1, xs.tail)..

end

val length [a] (xs: mlist a) : int = length_aux (0, xs)

. .

initially:

xs @ mlist a

39 / 83

(73)

match xs with..

| MNil ->..

accu..

| MCons ->..

length_aux (accu + 1, xs.tail)..

end

val length [a] (xs: mlist a) : int = length_aux (0, xs)

. .

upon entry into the first branch:

xs @ MNil

39 / 83

(74)

match xs with..

| MNil ->..

accu..

| MCons ->..

length_aux (accu + 1, xs.tail)..

end

val length [a] (xs: mlist a) : int = length_aux (0, xs)

. .

upon exit of the first branch:

xs @ MNil

39 / 83

(75)

match xs with..

| MNil ->..

accu..

| MCons ->..

length_aux (accu + 1, xs.tail)..

end

val length [a] (xs: mlist a) : int = length_aux (0, xs)

. .

upon exit of the first branch:

xs @ mlist a

39 / 83

(76)

match xs with..

| MNil ->..

accu..

| MCons ->..

length_aux (accu + 1, xs.tail)..

end

val length [a] (xs: mlist a) : int = length_aux (0, xs)

. .

upon entry into the second branch:

xs @ MCons { head = h; tail = t } h @ a

t @ mlist a

39 / 83

(77)

match xs with..

| MNil ->..

accu..

| MCons ->..

length_aux (accu + 1, xs.tail)..

end

val length [a] (xs: mlist a) : int = length_aux (0, xs)

. .

after the call, nothing has changed:

xs @ MCons { head = h; tail = t } h @ a

t @ mlist a

39 / 83

(78)

match xs with..

| MNil ->..

accu..

| MCons ->..

length_aux (accu + 1, xs.tail)..

end

val length [a] (xs: mlist a) : int = length_aux (0, xs)

. .

thus, by recombining:

xs @ MCons { head: a; tail: mlist a }

39 / 83

(79)

match xs with..

| MNil ->..

accu..

| MCons ->..

length_aux (accu + 1, xs.tail)..

end

val length [a] (xs: mlist a) : int = length_aux (0, xs)

. .

thus, by folding:

xs @ mlist a

39 / 83

(80)

This is atail-recursivefunction, i.e., a loop in disguise.

As we go, there is alistahead of us and alist segmentbehind us.

Ownership of the latter isimplicit, i.e., framed out.

Recursive reasoning, iterative execution.

(Now skipping ahead...)

40 / 83

(81)

Melding mutable lists

41 / 83

(82)

val rec meld_aux [a]

(xs:..MCons { head: a; tail: mlist a },

consumes..ys: mlist a) : () = match xs.tail with

| MNil ->..

xs.tail <- ys..

| MCons ->..

meld_aux (xs.tail, ys)..

end

.

42 / 83

(83)

val rec meld_aux [a]

(xs:..MCons { head: a; tail: mlist a },

consumes..ys: mlist a) : () = match xs.tail with

| MNil ->..

xs.tail <- ys..

| MCons ->..

meld_aux (xs.tail, ys)..

end

. .

42 / 83

(84)

val rec meld_aux [a]

(xs:..MCons { head: a; tail: mlist a },

consumes..ys: mlist a) : () = match xs.tail with

| MNil ->..

xs.tail <- ys..

| MCons ->..

meld_aux (xs.tail, ys)..

end

. .

42 / 83

(85)

val rec meld_aux [a]

(xs:..MCons { head: a; tail: mlist a },

consumes..ys: mlist a) : () = match xs.tail with

| MNil ->..

xs.tail <- ys..

| MCons ->..

meld_aux (xs.tail, ys)..

end

. .

42 / 83

(86)

val rec meld_aux [a]

(xs:..MCons { head: a; tail: mlist a },

consumes..ys: mlist a) : () = match xs.tail with

| MNil ->..

xs.tail <- ys..

| MCons ->..

meld_aux (xs.tail, ys)..

end

. .

42 / 83

(87)

val rec meld_aux [a]

(xs:..MCons { head: a; tail: mlist a },

consumes..ys: mlist a) : () = match xs.tail with

| MNil ->..

xs.tail <- ys..

| MCons ->..

meld_aux (xs.tail, ys)..

end

. .

42 / 83

(88)

val rec meld_aux [a]

(xs:..MCons { head: a; tail: mlist a },

consumes..ys: mlist a) : () = match xs.tail with

| MNil ->..

xs.tail <- ys..

| MCons ->..

meld_aux (xs.tail, ys)..

end

. .

42 / 83

(89)

val rec meld_aux [a]

(xs:..MCons { head: a; tail: mlist a },

consumes..ys: mlist a) : () = match xs.tail with

| MNil ->..

xs.tail <- ys..

| MCons ->..

meld_aux (xs.tail, ys)..

end

. .

42 / 83

(90)

val rec meld_aux [a]

(xs:..MCons { head: a; tail: mlist a },

consumes..ys: mlist a) : () = match xs.tail with

| MNil ->..

xs.tail <- ys..

| MCons ->..

meld_aux (xs.tail, ys)..

end

. .

42 / 83

(91)

val rec meld_aux [a]

(xs:..MCons { head: a; tail: mlist a },

consumes..ys: mlist a) : () = match xs.tail with

| MNil ->..

xs.tail <- ys..

| MCons ->..

meld_aux (xs.tail, ys)..

end

. .

42 / 83

(92)

val rec meld_aux [a]

(xs:..MCons { head: a; tail: mlist a },

consumes..ys: mlist a) : () = match xs.tail with

| MNil ->..

xs.tail <- ys..

| MCons ->..

meld_aux (xs.tail, ys)..

end

. .

42 / 83

(93)

val meld [a] (consumes xs: mlist a,

consumes ys: mlist a) : mlist a = match xs with

| MNil -> ys

| MCons -> meld_aux (xs, ys); xs end

43 / 83

(94)

Concatenating immutable lists

44 / 83

(95)

tail type:MCons { head: a; tail: () }

. .

Cons head..

tail

An isolatedConscell:

immutable,

notthe start of a well-formed list,

type:Cons { head: a; tail = t }

. .

Cons head..

tail

Alistcell:

immutable,

the start of a well-formed list,

typelist a

45 / 83

(96)

. .

head..

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

xs

.

ys

46 / 83

(97)

. .

head..

tail

.

. head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

xs

.

ys

46 / 83

Références

Documents relatifs

What many authors (e.g. Vetter) see as an advantage of data modelling(exactly this coming- into-being of a corporate, unied terminology) often turns out to be a disadvantage: the

El Data Sharing consiste en la actividad de fa- cilitar los datos de una investigación para que puedan ser utilizados por otros investigadores.. Es decir, se trata de compartir

Informing users and stakeholders of field spectroscopy datasets of the impact of high-quality data and metadata in the context of Earth observing data systems is an

Algebraic data structures Sharing mutable data Conclusion... A first example and a

Cur- rent access control systems are based on a predened set of static rules in order to prohibit access to certain elds of a data repository; these access control rules cannot

Apart from its usage in EUDAT B2FIND, the OAI- PMH endpoint for ISIS ICAT and the appropriate metadata mapping are being tested for the new Research Data Discovery

This tutorial will present the work that has been done in the context of one of the Spanish normalization working groups towards the definition of an open data maturity model

In particular, we compare three regulatory schemes: (i) imposing the integrated marketplace to share its information with the other delivery operator which in turn will lower