• Aucun résultat trouvé

Visitors Unchained Using

N/A
N/A
Protected

Academic year: 2022

Partager "Visitors Unchained Using"

Copied!
75
0
0

Texte intégral

(1)

Visitors Unchained

Usingvisitors

to traverseabstract syntax with binding

François Pottier

Inria Paris May 22, 2017

(2)

Visitors

(3)

Installation & configuration

Installation:

o p a m u p d a t e

o p a m i n s t a l l v i s i t o r s

To configure ocamlbuild, add this in_tags:

t r u e : \

p a c k a g e ( v i s i t o r s . ppx ) , \ p a c k a g e ( v i s i t o r s . r u n t i m e )

To configure Merlin, add this in.merlin:

PKG v i s i t o r s . ppx PKG v i s i t o r s . r u n t i m e

(4)

An “iter” visitor

Annotating a type definition with[@@deriving visitors { ... }]...

t y p e e x p r =

| E C o n s t of int

| E A d d of e x p r * e x p r

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " i t e r " }]

c l a s s v i r t u a l [ ’ s e l f ] i t e r = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . i t e r

m e t h o d v i s i t _ E C o n s t env c0 = l e t r0 = s e l f # v i s i t _ i n t env c0 in ()

m e t h o d v i s i t _ E A d d env c0 c1 = l e t r0 = s e l f # v i s i t _ e x p r env c0 in l e t r1 = s e l f # v i s i t _ e x p r env c1 in ()

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d ( c0 , c1 ) - >

s e l f # v i s i t _ E A d d env c0 c1 e n d

... causes avisitor classto be auto-generated.

(5)

An “iter” visitor

Annotating a type definition with[@@deriving visitors { ... }]...

t y p e e x p r =

| E C o n s t of int

| E A d d of e x p r * e x p r

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " i t e r " }]

c l a s s v i r t u a l [ ’ s e l f ] i t e r = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . i t e r

m e t h o d v i s i t _ E C o n s t env c0 = l e t r0 = s e l f # v i s i t _ i n t env c0 in ()

m e t h o d v i s i t _ E A d d env c0 c1 = l e t r0 = s e l f # v i s i t _ e x p r env c0 in l e t r1 = s e l f # v i s i t _ e x p r env c1 in ()

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d ( c0 , c1 ) - >

s e l f # v i s i t _ E A d d env c0 c1 e n d

... causes avisitor classto be auto-generated.

(6)

An “iter” visitor

Annotating a type definition with[@@deriving visitors { ... }]...

t y p e e x p r =

| E C o n s t of int

| E A d d of e x p r * e x p r

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " i t e r " }]

c l a s s v i r t u a l [ ’ s e l f ] i t e r = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . i t e r

m e t h o d v i s i t _ E C o n s t env c0 = l e t r0 = s e l f # v i s i t _ i n t env c0 in ()

m e t h o d v i s i t _ E A d d env c0 c1 = l e t r0 = s e l f # v i s i t _ e x p r env c0 in l e t r1 = s e l f # v i s i t _ e x p r env c1 in ()

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d ( c0 , c1 ) - >

s e l f # v i s i t _ E A d d env c0 c1 e n d

... causes avisitor classto be auto-generated.

one method per data constructor

(7)

An “iter” visitor

Annotating a type definition with[@@deriving visitors { ... }]...

t y p e e x p r =

| E C o n s t of int

| E A d d of e x p r * e x p r

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " i t e r " }]

c l a s s v i r t u a l [ ’ s e l f ] i t e r = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . i t e r

m e t h o d v i s i t _ E C o n s t env c0 = l e t r0 = s e l f # v i s i t _ i n t env c0 in ()

m e t h o d v i s i t _ E A d d env c0 c1 = l e t r0 = s e l f # v i s i t _ e x p r env c0 in l e t r1 = s e l f # v i s i t _ e x p r env c1 in ()

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d ( c0 , c1 ) - >

s e l f # v i s i t _ E A d d env c0 c1 e n d

... causes avisitor classto be auto-generated.

one method per data type

(8)

An “iter” visitor

Annotating a type definition with[@@deriving visitors { ... }]...

t y p e e x p r =

| E C o n s t of int

| E A d d of e x p r * e x p r

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " i t e r " }]

c l a s s v i r t u a l [ ’ s e l f ] i t e r = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . i t e r

m e t h o d v i s i t _ E C o n s t env c0 = l e t r0 = s e l f # v i s i t _ i n t env c0 in ()

m e t h o d v i s i t _ E A d d env c0 c1 = l e t r0 = s e l f # v i s i t _ e x p r env c0 in l e t r1 = s e l f # v i s i t _ e x p r env c1 in ()

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d ( c0 , c1 ) - >

s e l f # v i s i t _ E A d d env c0 c1 e n d

... causes avisitor classto be auto-generated.

an environment is pushed down

(9)

An “iter” visitor

Annotating a type definition with[@@deriving visitors { ... }]...

t y p e e x p r =

| E C o n s t of int

| E A d d of e x p r * e x p r

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " i t e r " }]

c l a s s v i r t u a l [ ’ s e l f ] i t e r = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . i t e r

m e t h o d v i s i t _ E C o n s t env c0 = l e t r0 = s e l f # v i s i t _ i n t env c0 in ()

m e t h o d v i s i t _ E A d d env c0 c1 = l e t r0 = s e l f # v i s i t _ e x p r env c0 in l e t r1 = s e l f # v i s i t _ e x p r env c1 in ()

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d ( c0 , c1 ) - >

s e l f # v i s i t _ E A d d env c0 c1 e n d

... causes avisitor classto be auto-generated.

default behavior is to do nothing

(10)

An “iter” visitor

Annotating a type definition with[@@deriving visitors { ... }]...

t y p e e x p r =

| E C o n s t of int

| E A d d of e x p r * e x p r

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " i t e r " }]

c l a s s v i r t u a l [ ’ s e l f ] i t e r = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . i t e r

m e t h o d v i s i t _ E C o n s t env c0 = l e t r0 = s e l f # v i s i t _ i n t env c0 in ()

m e t h o d v i s i t _ E A d d env c0 c1 = l e t r0 = s e l f # v i s i t _ e x p r env c0 in l e t r1 = s e l f # v i s i t _ e x p r env c1 in ()

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d ( c0 , c1 ) - >

s e l f # v i s i t _ E A d d env c0 c1 e n d

... causes avisitor classto be auto-generated.

behavior at type intis inherited

(11)

A “map” visitor

There are several varieties of visitors:

t y p e e x p r =

| E C o n s t of int

| E A d d of e x p r * e x p r

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " map " }]

c l a s s v i r t u a l [ ’ s e l f ] map = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . map

m e t h o d v i s i t _ E C o n s t env c0 = l e t r0 = s e l f # v i s i t _ i n t env c0 in E C o n s t r0

m e t h o d v i s i t _ E A d d env c0 c1 = l e t r0 = s e l f # v i s i t _ e x p r env c0 in l e t r1 = s e l f # v i s i t _ e x p r env c1 in E A d d ( r0 , r1 )

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d ( c0 , c1 ) - >

s e l f # v i s i t _ E A d d env c0 c1 e n d

default behavior is to rebuild a tree

a “map” visitor is requested

(12)

Using a “map” visitor

Inherita visitor class andoverrideone or more methods:

l e t add e1 e2 = (* A s m a r t c o n s t r u c t o r . *) m a t c h e1 , e2 w i t h

| E C o n s t 0 , e

| e , E C o n s t 0 - > e

| _ , _ - > E A d d ( e1 , e2 )

l e t o p t i m i z e : e x p r - > e x p r = l e t v = o b j e c t ( s e l f )

i n h e r i t [ _ ] map

m e t h o d! v i s i t _ E A d d env e1 e2 = add

( s e l f # v i s i t _ e x p r env e1 ) ( s e l f # v i s i t _ e x p r env e2 ) e n d in

v # v i s i t _ e x p r ()

This addition-optimization pass isunchangedif more expression forms are added.

(13)

A “reduce” visitor

Here is another variety:

t y p e e x p r =

| E C o n s t of ( int [ @ o p a q u e ] )

| E A d d of e x p r * e x p r

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " r e d u c e " }]

c l a s s v i r t u a l [ ’ s e l f ] r e d u c e = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . r e d u c e

m e t h o d v i s i t _ E C o n s t env c0 =

l e t s0 = (f u n t h i s - > s e l f # z e r o ) c0 in s0

m e t h o d v i s i t _ E A d d env c0 c1 = l e t s0 = s e l f # v i s i t _ e x p r env c0 in l e t s1 = s e l f # v i s i t _ e x p r env c1 in s e l f # p l u s s0 s1

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d ( c0 , c1 ) - >

s e l f # v i s i t _ E A d d env c0 c1 e n d

a “reduce” visitor is requested

results combined usingzero/plus

(14)

A “reduce” visitor

Here is another variety:

t y p e e x p r =

| E C o n s t of ( int [ @ o p a q u e ] )

| E A d d of e x p r * e x p r

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " r e d u c e " }]

c l a s s v i r t u a l [ ’ s e l f ] r e d u c e = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . r e d u c e

m e t h o d v i s i t _ E C o n s t env c0 =

l e t s0 = (f u n t h i s - > s e l f # z e r o ) c0 in s0

m e t h o d v i s i t _ E A d d env c0 c1 = l e t s0 = s e l f # v i s i t _ e x p r env c0 in l e t s1 = s e l f # v i s i t _ e x p r env c1 in s e l f # p l u s s0 s1

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d ( c0 , c1 ) - >

s e l f # v i s i t _ E A d d env c0 c1 e n d

@opaquesubtrees are not visited

(15)

A “reduce” visitor

Here is another variety:

t y p e e x p r =

| E C o n s t of ( int [ @ o p a q u e ] )

| E A d d of e x p r * e x p r

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " r e d u c e " }]

c l a s s v i r t u a l [ ’ s e l f ] r e d u c e = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . r e d u c e

m e t h o d v i s i t _ E C o n s t env c0 =

l e t s0 = (f u n t h i s - > s e l f # z e r o ) c0 in s0

m e t h o d v i s i t _ E A d d env c0 c1 = l e t s0 = s e l f # v i s i t _ e x p r env c0 in l e t s1 = s e l f # v i s i t _ e x p r env c1 in s e l f # p l u s s0 s1

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d ( c0 , c1 ) - >

s e l f # v i s i t _ E A d d env c0 c1 e n d

class is polymorphic in env and monoid

look Ma, full type inference!

(16)

Using a “reduce” visitor

Inheritthe visitor,inherita monoid,overrideone or more methods:

l e t s i z e : e x p r - > int = l e t v = o b j e c t

i n h e r i t [ _ ] r e d u c e as s u p e r

i n h e r i t [ _ ] V i s i t o r s R u n t i m e . a d d i t i o n _ m o n o i d m e t h o d! v i s i t _ e x p r env e =

1 + s u p e r # v i s i t _ e x p r env e e n d in

v # v i s i t _ e x p r ()

This size computation remainsunchangedif more expression forms are added.

(17)

What we have seen so far

I Several built-in varieties:iter,map,endo,reduce,mapreduce,fold

I Arity two, too:iter2,map2,reduce2,mapreduce2,fold2

I Monomorphicvisitor methods,polymorphicvisitor classes

I All typesinferred

(18)

Support for parameterized data types

We wish to traverse parameterized data types, too.

I But: how does one traverse a subtree of type’a?

Two approaches are supported:

I declare avirtual visitor methodvisit_’a

I ’ais treated as a fixed/unknown type, not really as a parameter

I pass afunctionvisit_’ato every visitor method.

I allows / requires methods to be polymorphic in’a

I more compositional

In this talk: monomorphic generated methods, polymorphic hand-written methods.

(19)

A visitor for a parameterized type

Here is a “monomorphic-method” visitor for a parameterized type:

t y p e ’ i n f o e x p r _ n o d e =

| E C o n s t of int

| E A d d of ’ i n f o e x p r * ’ i n f o e x p r a n d ’ i n f o e x p r =

{ i n f o : ’ i n f o ; n o d e : ’ i n f o e x p r _ n o d e } [ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " map " }]

c l a s s v i r t u a l [ ’ s e l f ] map = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . map

m e t h o d v i r t u a l visit_ ’ i n f o : _ m e t h o d v i s i t _ E C o n s t = ...

m e t h o d v i s i t _ E A d d = ...

m e t h o d v i s i t _ e x p r _ n o d e = ...

m e t h o d v i s i t _ e x p r env t h i s =

l e t r0 = s e l f # visit_ ’ i n f o env t h i s . i n f o in l e t r1 = s e l f # v i s i t _ e x p r _ n o d e env t h i s . n o d e in { i n f o = r0 ; n o d e = r1 }

e n d

The type ofvisit_’infois’env -> ’info1 -> ’info2.

(20)

A visitor for a parameterized type

Here is a “monomorphic-method” visitor for a parameterized type:

t y p e ’ i n f o e x p r _ n o d e =

| E C o n s t of int

| E A d d of ’ i n f o e x p r * ’ i n f o e x p r a n d ’ i n f o e x p r =

{ i n f o : ’ i n f o ; n o d e : ’ i n f o e x p r _ n o d e } [ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " map " }]

c l a s s v i r t u a l [ ’ s e l f ] map = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . map

m e t h o d v i r t u a l visit_ ’ i n f o : _ m e t h o d v i s i t _ E C o n s t = ...

m e t h o d v i s i t _ E A d d = ...

m e t h o d v i s i t _ e x p r _ n o d e = ...

m e t h o d v i s i t _ e x p r env t h i s =

l e t r0 = s e l f # visit_ ’ i n f o env t h i s . i n f o in l e t r1 = s e l f # v i s i t _ e x p r _ n o d e env t h i s . n o d e in { i n f o = r0 ; n o d e = r1 }

e n d

a virtual method is declared / used

The type ofvisit_’infois’env -> ’info1 -> ’info2.

(21)

Using a visitor for a parameterized type

This visitor can mapundecoratedexpressions todecoratedexpressions:

l e t n u m b e r ( e : _ e x p r ) : int e x p r = l e t v = o b j e c t

i n h e r i t [ _ ] map v a l m u t a b l e c o u n t = 0

m e t h o d visit_ ’ i n f o _ e n v _ i n f o = l e t c = c o u n t in c o u n t < - c + 1; c e n d in

v # v i s i t _ e x p r () e

and vice-versa:

l e t s t r i p ( e : _ e x p r ) : u n i t e x p r = l e t v = o b j e c t

i n h e r i t [ _ ] map

m e t h o d visit_ ’ i n f o _ e n v _ i n f o = () e n d in

v # v i s i t _ e x p r () e

The visitor class ispolymorphicin’env,’info1and’info2.

(22)

A “mapreduce” visitor for a parameterized type

Here is another variety of visitor for this parameterized type:

t y p e ’ i n f o e x p r _ n o d e =

| E C o n s t of int

| E A d d of ’ i n f o e x p r * ’ i n f o e x p r a n d ’ i n f o e x p r =

{ i n f o : ’ i n f o ; n o d e : ’ i n f o e x p r _ n o d e }

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " m a p r e d u c e " }]

c l a s s v i r t u a l [ ’ s e l f ] m a p r e d u c e = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . m a p r e d u c e

m e t h o d v i r t u a l visit_ ’ i n f o : _ m e t h o d v i s i t _ E C o n s t = ...

m e t h o d v i s i t _ E A d d env c0 c1 =

l e t r0 , s0 = s e l f # v i s i t _ e x p r env c0 in l e t r1 , s1 = s e l f # v i s i t _ e x p r env c1 in E A d d ( r0 , r1 ) , s e l f # p l u s s0 s1

m e t h o d v i s i t _ e x p r _ n o d e = ...

m e t h o d v i s i t _ e x p r = ...

e n d

Every method returns apairof a subtree and a summary.

a “mapreduce” visitor is requested

(23)

Using a visitor for a parameterized type

This visitor canannotateevery subexpressionwith its size:

l e t a n n o t a t e ( e : _ e x p r ) : int e x p r = l e t v = o b j e c t

i n h e r i t [ _ ] m a p r e d u c e as s u p e r

i n h e r i t [ _ ] V i s i t o r s R u n t i m e . a d d i t i o n _ m o n o i d m e t h o d! v i s i t _ e x p r env { i n f o = _ ; n o d e } =

l e t node , s i z e = s u p e r # v i s i t _ e x p r _ n o d e env n o d e in l e t s i z e = s i z e + 1 in

{ i n f o = s i z e ; n o d e } , s i z e m e t h o d visit_ ’ i n f o _ e n v _ i n f o =

a s s e r t f a l s e (* n e v e r c a l l e d *) e n d in

l e t e , _ = v # v i s i t _ e x p r () e in e

(24)

Visiting preexisting types

Lists can be visited, too.

t y p e e x p r =

| E C o n s t of int

| E A d d of e x p r l i s t

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " i t e r " }]

c l a s s v i r t u a l [ ’ s e l f ] i t e r = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . i t e r

m e t h o d v i s i t _ E C o n s t env c0 = l e t r0 = s e l f # v i s i t _ i n t env c0 in ()

m e t h o d v i s i t _ E A d d env c0 =

l e t r0 = s e l f # v i s i t _ l i s t s e l f # v i s i t _ e x p r env c0 in ()

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d c0 - >

s e l f # v i s i t _ E A d d env c0 e n d

a preexisting parameterized type

(25)

Visiting preexisting types

Lists can be visited, too.

t y p e e x p r =

| E C o n s t of int

| E A d d of e x p r l i s t

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " i t e r " }]

c l a s s v i r t u a l [ ’ s e l f ] i t e r = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . i t e r

m e t h o d v i s i t _ E C o n s t env c0 = l e t r0 = s e l f # v i s i t _ i n t env c0 in ()

m e t h o d v i s i t _ E A d d env c0 =

l e t r0 = s e l f # v i s i t _ l i s t s e l f # v i s i t _ e x p r env c0 in ()

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d c0 - >

s e l f # v i s i t _ E A d d env c0 e n d

visitor method is passed a visitor function

(26)

Visiting preexisting types

Lists can be visited, too.

t y p e e x p r =

| E C o n s t of int

| E A d d of e x p r l i s t

[ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " i t e r " }]

c l a s s v i r t u a l [ ’ s e l f ] i t e r = o b j e c t ( s e l f : ’ s e l f ) i n h e r i t [ _ ] V i s i t o r s R u n t i m e . i t e r

m e t h o d v i s i t _ E C o n s t env c0 = l e t r0 = s e l f # v i s i t _ i n t env c0 in ()

m e t h o d v i s i t _ E A d d env c0 =

l e t r0 = s e l f # v i s i t _ l i s t s e l f # v i s i t _ e x p r env c0 in ()

m e t h o d v i s i t _ e x p r env t h i s = m a t c h t h i s w i t h

| E C o n s t c0 - >

s e l f # v i s i t _ E C o n s t env c0

| E A d d c0 - >

s e l f # v i s i t _ E A d d env c0 e n d

visitor method is inherited

(27)

Predefined visitor methods

The classVisitorsRuntime.mapoffers this method:

c l a s s [ ’ s e l f ] map = o b j e c t ( s e l f ) (* One of m a n y p r e d e f i n e d m e t h o d s : *) m e t h o d p r i v a t e v i s i t _ l i s t : ’ env ’ a ’ b .

( ’ env - > ’ a - > ’ b ) - > ’ env - > ’ a l i s t - > ’ b l i s t

= f u n f env xs - >

m a t c h xs w i t h

| [] - >

[]

| x :: xs - >

l e t x = f env x in

x :: s e l f # v i s i t _ l i s t f env xs e n d

This method ispolymorphic, so multiple instances oflistare not a problem.

(28)

Visitors – a summary

Although they follow fixed patterns, visitors are quiteversatile.

They are like higher-order functions, only morecustomizableandcomposable.

More fun with visitors:

I visitors foropen data typesand their fixed points(link);

I visitors forhash-consed data structures(link);

I iteratorsout of visitors(link).

In the remainder of this talk:

I Can we traverseabstract syntax with binding?

(29)

Visitors Unchained

(30)

Dealing with binding

Can a visitor traverseabstract syntax with bindingconstructs?

Can this be done in amodularway?

Exactly whichseparation of concernsshould one enforce?

I There are manybinding constructs,

I there are evencombinator languagesfor describing binding structure!

I and many commonoperationson terms,

I often specific of onerepresentationof names and binders,

I sometimes specific oftwosuch representations, e.g.,conversions.

I Can we insulate theend userfrom this complexity? We suggest distinguishingthreeprincipals...

(31)

Dealing with binding

Can a visitor traverseabstract syntax with bindingconstructs?

Can this be done in amodularway?

Exactly whichseparation of concernsshould one enforce?

I There are manybinding constructs,

I there are evencombinator languagesfor describing binding structure!

I and many commonoperationson terms,

I often specific of onerepresentationof names and binders,

I sometimes specific oftwosuch representations, e.g.,conversions.

I Can we insulate theend userfrom this complexity? We suggest distinguishingthreeprincipals...

(32)

Dealing with binding

Can a visitor traverseabstract syntax with bindingconstructs?

Can this be done in amodularway?

Exactly whichseparation of concernsshould one enforce?

I There are manybinding constructs,

I there are evencombinator languagesfor describing binding structure!

I and many commonoperationson terms,

I often specific of onerepresentationof names and binders,

I sometimes specific oftwosuch representations, e.g.,conversions.

I Can we insulate theend userfrom this complexity? We suggest distinguishingthreeprincipals...

(33)

Dealing with binding

Can a visitor traverseabstract syntax with bindingconstructs?

Can this be done in amodularway?

Exactly whichseparation of concernsshould one enforce?

I There are manybinding constructs,

I there are evencombinator languagesfor describing binding structure!

I and many commonoperationson terms,

I often specific of onerepresentationof names and binders,

I sometimes specific oftwosuch representations, e.g.,conversions.

I Can we insulate theend userfrom this complexity?

We suggest distinguishingthreeprincipals...

(34)
(35)

end user

(36)

end user

operations specialist

(37)

end user

operations specialist

binder maestro

(38)

The end user

(39)

Desiderata

The end user wishes:

I to describe the structure of ASTs in a concise anddeclarativestyle,

I not to be bothered with implementation details,

I possibly to have access toseveral representationsof names,

I to get access to a toolkit ofready-made operationson terms.

(40)

Example: abstract syntax of the λ -calculus

Let the type(’bn, ’term) absbe a synonym for’bn * ’term.

The end user defines his syntax as follows:

t y p e ( ’ bn , ’ fn ) t e r m =

| T V a r of ’ fn

| T L a m b d a of ( ’ bn , ( ’ bn , ’ fn ) t e r m ) abs

| T A p p of ( ’ bn , ’ fn ) t e r m * ( ’ bn , ’ fn ) t e r m [ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " map " ;

a n c e s t o r s = [ " B i n d i n g F o r m s . map " ] }]

t y p e r a w _ t e r m = ( string , s t r i n g ) t e r m t y p e n o m i n a l _ t e r m = ( A t o m . t , A t o m . t ) t e r m t y p e d e b r u i j n _ t e r m = ( unit , int ) t e r m

He getsmultiple representationsof names.

I At least two are used in any single application. (Parsing. Printing.) He getsvisitorsfor free. The methodvisit_absis used at abstractions.

I iter,map,iter2needed in practice. Focusing onmapin this talk.

(41)

Example: abstract syntax of the λ -calculus

Let the type(’bn, ’term) absbe a synonym for’bn * ’term.

The end user defines his syntax as follows:

t y p e ( ’ bn , ’ fn ) t e r m =

| T V a r of ’ fn

| T L a m b d a of ( ’ bn , ( ’ bn , ’ fn ) t e r m ) abs

| T A p p of ( ’ bn , ’ fn ) t e r m * ( ’ bn , ’ fn ) t e r m [ @ @ d e r i v i n g v i s i t o r s { v a r i e t y = " map " ;

a n c e s t o r s = [ " B i n d i n g F o r m s . map " ] }]

t y p e r a w _ t e r m = ( string , s t r i n g ) t e r m t y p e n o m i n a l _ t e r m = ( A t o m . t , A t o m . t ) t e r m t y p e d e b r u i j n _ t e r m = ( unit , int ) t e r m

He getsmultiple representationsof names.

I At least two are used in any single application. (Parsing. Printing.) He getsvisitorsfor free. The methodvisit_absis used at abstractions.

I iter,map,iter2needed in practice. Focusing onmapin this talk.

provided by the binder maestro

(42)

The binder

maestro

(43)

An easy job?

Implementingvisit_absis the task of our sophisticated binder maestro.

The key is toextend the environmentwhen entering the scope of a binder.

Easy?

Maybe — yet, the binder maestro:

I does not knowwhat operationis being performed,

I does not knowwhat representation(s)of names are in use,

I therefore does not know the types of names and environments,

I let alonehowto extend the environment.

What he knows iswhereandwith what namesto extend the environment.

(44)

An easy job?

Implementingvisit_absis the task of our sophisticated binder maestro.

The key is toextend the environmentwhen entering the scope of a binder.

Easy? Maybe — yet, the binder maestro:

I does not knowwhat operationis being performed,

I does not knowwhat representation(s)of names are in use,

I therefore does not know the types of names and environments,

I let alonehowto extend the environment.

What he knows iswhereandwith what namesto extend the environment.

(45)

A convention

The binder maestro agrees on adealwith the operations specialist.

“I tell you when to extend the environment; you do the dirty work.”

The binder maestrocallsa method which the operations specialistprovides:

(* A h o o k t h a t d e f i n e s how to e x t e n d the e n v i r o n m e n t . *) m e t h o d p r i v a t e v i r t u a l e x t e n d : ’ env - > ’ bn1 - > ’ env * ’ bn2 This is a bare-bonesAPIfor describing binding constructs.

(46)

Visiting an abstraction

The classBindingForms.mapoffers the methodvisit_abs:

c l a s s v i r t u a l [ ’ s e l f ] map = o b j e c t ( s e l f : ’ s e l f ) (* A v i s i t o r m e t h o d for the t y p e abs . *)

m e t h o d p r i v a t e v i s i t _ a b s : ’ t e r m 1 ’ t e r m 2 . _ - >

( ’ env - > ’ t e r m 1 - > ’ t e r m 2 ) - >

’ env - > ( ’ bn1 , ’ t e r m 1 ) abs - > ( ’ bn2 , ’ t e r m 2 ) abs

= f u n _ visit_ ’ t e r m env ( x1 , t1 ) - >

l e t env , x2 = s e l f # e x t e n d env x1 in l e t t2 = visit_ ’ t e r m env t1 in x2 , t2

(* A h o o k t h a t d e f i n e s how to e x t e n d the e n v i r o n m e n t . *) m e t h o d p r i v a t e v i r t u a l e x t e n d : ’ env - > ’ bn1 - > ’ env * ’ bn2 e n d

This method:

I takes avisitor functionfor terms, anenvironment,

I an abstraction, i.e., apairof a name and a term, and

I returns a pair of atransformed nameand atransformed term.

(47)

Visiting an abstraction

The classBindingForms.mapoffers the methodvisit_abs:

c l a s s v i r t u a l [ ’ s e l f ] map = o b j e c t ( s e l f : ’ s e l f ) (* A v i s i t o r m e t h o d for the t y p e abs . *)

m e t h o d p r i v a t e v i s i t _ a b s : ’ t e r m 1 ’ t e r m 2 . _ - >

( ’ env - > ’ t e r m 1 - > ’ t e r m 2 ) - >

’ env - > ( ’ bn1 , ’ t e r m 1 ) abs - > ( ’ bn2 , ’ t e r m 2 ) abs

= f u n _ visit_ ’ t e r m env ( x1 , t1 ) - >

l e t env , x2 = s e l f # e x t e n d env x1 in l e t t2 = visit_ ’ t e r m env t1 in x2 , t2

(* A h o o k t h a t d e f i n e s how to e x t e n d the e n v i r o n m e n t . *) m e t h o d p r i v a t e v i r t u a l e x t e n d : ’ env - > ’ bn1 - > ’ env * ’ bn2 e n d

This method:

I takes avisitor functionfor terms, anenvironment,

I an abstraction, i.e., apairof a name and a term, and

I returns a pair of atransformed nameand atransformed term.

(48)

Visiting an abstraction

The classBindingForms.mapoffers the methodvisit_abs:

c l a s s v i r t u a l [ ’ s e l f ] map = o b j e c t ( s e l f : ’ s e l f ) (* A v i s i t o r m e t h o d for the t y p e abs . *)

m e t h o d p r i v a t e v i s i t _ a b s : ’ t e r m 1 ’ t e r m 2 . _ - >

( ’ env - > ’ t e r m 1 - > ’ t e r m 2 ) - >

’ env - > ( ’ bn1 , ’ t e r m 1 ) abs - > ( ’ bn2 , ’ t e r m 2 ) abs

= f u n _ visit_ ’ t e r m env ( x1 , t1 ) - >

l e t env , x2 = s e l f # e x t e n d env x1 in l e t t2 = visit_ ’ t e r m env t1 in x2 , t2

(* A h o o k t h a t d e f i n e s how to e x t e n d the e n v i r o n m e n t . *) m e t h o d p r i v a t e v i r t u a l e x t e n d : ’ env - > ’ bn1 - > ’ env * ’ bn2 e n d

This method:

I takes avisitor functionfor terms, anenvironment,

I an abstraction, i.e., apairof a name and a term, and

I returns a pair of atransformed nameand atransformed term.

(49)

Visiting an abstraction

The classBindingForms.mapoffers the methodvisit_abs:

c l a s s v i r t u a l [ ’ s e l f ] map = o b j e c t ( s e l f : ’ s e l f ) (* A v i s i t o r m e t h o d for the t y p e abs . *)

m e t h o d p r i v a t e v i s i t _ a b s : ’ t e r m 1 ’ t e r m 2 . _ - >

( ’ env - > ’ t e r m 1 - > ’ t e r m 2 ) - >

’ env - > ( ’ bn1 , ’ t e r m 1 ) abs - > ( ’ bn2 , ’ t e r m 2 ) abs

= f u n _ visit_ ’ t e r m env ( x1 , t1 ) - >

l e t env , x2 = s e l f # e x t e n d env x1 in l e t t2 = visit_ ’ t e r m env t1 in x2 , t2

(* A h o o k t h a t d e f i n e s how to e x t e n d the e n v i r o n m e n t . *) m e t h o d p r i v a t e v i r t u a l e x t e n d : ’ env - > ’ bn1 - > ’ env * ’ bn2 e n d

This method:

I takes avisitor functionfor terms, anenvironment,

I an abstraction, i.e., apairof a name and a term, and

I returns a pair of atransformed nameand atransformed term.

(50)

Visiting an abstraction

The classBindingForms.mapoffers the methodvisit_abs:

c l a s s v i r t u a l [ ’ s e l f ] map = o b j e c t ( s e l f : ’ s e l f ) (* A v i s i t o r m e t h o d for the t y p e abs . *)

m e t h o d p r i v a t e v i s i t _ a b s : ’ t e r m 1 ’ t e r m 2 . _ - >

( ’ env - > ’ t e r m 1 - > ’ t e r m 2 ) - >

’ env - > ( ’ bn1 , ’ t e r m 1 ) abs - > ( ’ bn2 , ’ t e r m 2 ) abs

= f u n _ visit_ ’ t e r m env ( x1 , t1 ) - >

l e t env , x2 = s e l f # e x t e n d env x1 in l e t t2 = visit_ ’ t e r m env t1 in x2 , t2

(* A h o o k t h a t d e f i n e s how to e x t e n d the e n v i r o n m e n t . *) m e t h o d p r i v a t e v i r t u a l e x t e n d : ’ env - > ’ bn1 - > ’ env * ’ bn2 e n d

This method:

I takes avisitor functionfor terms, anenvironment,

I an abstraction, i.e., apairof a name and a term, and

I returns a pair of atransformed nameand atransformed term.

(51)

Visiting an abstraction

That’sall there isto single-name abstractions.

More binding constructs later on...

For now, let’s turn to the final participant.

(52)

The operations

specialist

(53)

A toolbox of operations

There are many operations on terms that the end user might wish for:

I testing terms forequalityup toα-equivalence,

I finding out which names arefreeorboundin a term,

I applying arenamingor asubstitutionto a term,

I convertinga term from one representation to another,

I (plus application-specific operations.)

(54)

Implementing an operation

To implement one operation, the specialist decides:

I thetypesof names and environments,

I what to doat afree nameoccurrence,

I how to extendthe environment when entering the scope of abound name.

(55)

Implementing import

As an example, let’s implementimport, which converts raw terms to nominal terms.

1. An import environment maps strings to atoms:

m o d u l e S t r i n g M a p = Map . M a k e ( S t r i n g ) t y p e env = A t o m . t S t r i n g M a p . t l e t e m p t y : env = S t r i n g M a p . e m p t y

(56)

Implementing import

2. When the scope ofxis entered,

the environment is extended with a mapping of the stringxto a fresh atoma.

l e t e x t e n d ( env : env ) ( x : s t r i n g ) : env * A t o m . t = l e t a = A t o m . f r e s h x in

l e t env = S t r i n g M a p . add x a env in env , a

(Anatomcarries a unique integer identity.)

This is true regardless of which binding constructs are traversed.

(57)

Implementing import

3. When an occurrence of the stringxis found,

the environment is looked up so as to find the corresponding atom.

e x c e p t i o n U n b o u n d of s t r i n g

l e t l o o k u p ( env : env ) ( x : s t r i n g ) : A t o m . t = t r y S t r i n g M a p . f i n d x env

w i t h N o t _ f o u n d - > r a i s e ( U n b o u n d x )

(58)

Implementing import

The previous instructions are grouped in a little class — a “kit”:

c l a s s [ ’ s e l f ] map = o b j e c t ( _ : ’ s e l f ) m e t h o d p r i v a t e e x t e n d = e x t e n d m e t h o d p r i v a t e visit_ ’ fn = l o o k u p e n d

This isKitImport.map.

That’s all there is to it...but...

(59)

The end user mustwork

a little bit toglueeverything together...

... and may feelslightly annoyed.

(60)

The end user mustwork

a little bit toglueeverything together...

... and may feelslightly annoyed.

(61)

Typical glue

For one operation, the end user must write 5 lines of glue code:

l e t i m p o r t _ t e r m env t = (o b j e c t

i n h e r i t [ _ ] map (* g e n e r a t e d by v i s i t o r s *) i n h e r i t [ _ ] K i t I m p o r t . map (* p r o v i d e d by A l p h a L i b *) e n d) # v i s i t _ t e r m env t

For 15 operations, this hurts.

Functorscan help in simple cases, but are not flexible enough.

Macroshelp, but are ugly. Is there a better way?

(62)

Towards advanced

binding constructs

(63)

Defining new binding constructs

There aremany binding constructsout there.

I “let”, “let rec”, patterns, telescopes, ...

We have seen how toprogrammaticallydefine a binding construct.

Can it be done in a moredeclarativemanner?

(64)

A domain-specific language

Here is a little language ofbinding combinators:

t ::= . . . sums, products, free occurrences of names, etc.

| abstraction(p) a pattern, with embedded subterms

| bind(p,t) — sugar for abstraction(p×inner(t))

p ::= . . . sums, products, etc.

| binder(x) a binding occurrence of a name

| outer(t) an embedded term

| rebind(p) a pattern in the scope of any bound names on the left

| inner(t) — sugar for rebind(outer(t))

Inspired by Cαml (F.P., 2005) and Unbound (Weirich et al., 2011).

(65)

A domain-specific language

Here is a little language ofbinding combinators:

t ::= . . . sums, products, free occurrences of names, etc.

| abstraction(p) a pattern, with embedded subterms

| bind(p,t) — sugar for abstraction(p×inner(t))

p ::= . . . sums, products, etc.

| binder(x) a binding occurrence of a name

| outer(t) an embedded term

| rebind(p) a pattern in the scope of any bound names on the left

| inner(t) — sugar for rebind(outer(t))

Inspired by Cαml (F.P., 2005) and Unbound (Weirich et al., 2011).

(66)

A domain-specific language

Here is a little language ofbinding combinators:

t ::= . . . sums, products, free occurrences of names, etc.

| abstraction(p) a pattern, with embedded subterms

| bind(p,t) — sugar for abstraction(p×inner(t))

p ::= . . . sums, products, etc.

| binder(x) a binding occurrence of a name

| outer(t) an embedded term

| rebind(p) a pattern in the scope of any bound names on the left

| inner(t) — sugar for rebind(outer(t))

Inspired by Cαml (F.P., 2005) and Unbound (Weirich et al., 2011).

(67)

Implementation

These primitive constructs are just annotations:

t y p e ’ p a b s t r a c t i o n = ’ p t y p e ’ bn b i n d e r = ’ bn t y p e ’ t o u t e r = ’ t t y p e ’ p r e b i n d = ’ p

Their presence triggers calls to appropriate (hand-written)visit_methods.

(68)

Implementation

While visiting a pattern, we keep track of:

I theouter environment, which existed outside this pattern;

I thecurrent environment, extended with the bound names encountered so far.

Thus, while visiting a pattern, we use a richer type ofcontexts:

t y p e ’ env c o n t e x t = { o u t e r : ’ env ; c u r r e n t : ’ env ref }

— Not every visitor method need have the same type of environments!

With this in mind, the implementation of thevisit_methods is straightforward...

(69)

Implementation

This code takes place in amapvisitor:

c l a s s v i r t u a l [ ’ s e l f ] map = o b j e c t ( s e l f : ’ s e l f )

m e t h o d p r i v a t e v i r t u a l e x t e n d : ’ env - > ’ bn1 - > ’ env * ’ bn2 (* The f o u r v i s i t o r m e t h o d s are i n s e r t e d h e r e ... *)

e n d

1. At the root of an abstraction,a fresh contextis allocated:

m e t h o d p r i v a t e v i s i t _ a b s t r a c t i o n : ’ env ’ p1 ’ p2 . ( ’ env c o n t e x t - > ’ p1 - > ’ p2 ) - >

’ env - > ’ p1 a b s t r a c t i o n - > ’ p2 a b s t r a c t i o n

= f u n v i s i t _ p env p1 - >

v i s i t _ p { o u t e r = env ; c u r r e n t = ref env } p1

(70)

Implementation

2. When a bound name is met, thecurrentenvironment isextended:

m e t h o d p r i v a t e v i s i t _ b i n d e r : _ - >

’ env c o n t e x t - > ’ bn1 b i n d e r - > ’ bn2 b i n d e r

= f u n visit_ ’ bn ctx x1 - >

l e t env = !( ctx . c u r r e n t ) in

l e t env , x2 = s e l f # e x t e n d env x1 in ctx . c u r r e n t := env ;

x2

(71)

Implementation

3. When a term that isnot in the scopeof the abstraction is found, it is visited in theouterenvironment.

m e t h o d p r i v a t e v i s i t _ o u t e r : ’ env ’ t1 ’ t2 . ( ’ env - > ’ t1 - > ’ t2 ) - >

’ env c o n t e x t - > ’ t1 o u t e r - > ’ t2 o u t e r

= f u n v i s i t _ t ctx t1 - >

v i s i t _ t ctx . o u t e r t1

(72)

Implementation

4. When a subpattern markedrebindis found,

thecurrentenvironment is installed as theouterenvironment.

m e t h o d p r i v a t e v i s i t _ r e b i n d : ’ env ’ p1 ’ p2 . ( ’ env c o n t e x t - > ’ p1 - > ’ p2 ) - >

’ env c o n t e x t - > ’ p1 r e b i n d - > ’ p2 r e b i n d

= f u n v i s i t _ p ctx p1 - >

v i s i t _ p { ctx w i t h o u t e r = !( ctx . c u r r e n t ) } p1 This affects the meaning ofouterinsiderebind.

(73)

Example use: telescopes

A dependently-typedλ-calculus whoseΠandλforms involve a telescope:

# d e f i n e t e l e ( ’ bn , ’ fn ) t e l e

# d e f i n e t e r m ( ’ bn , ’ fn ) t e r m t y p e t e l e =

| T e l e N i l

| T e l e C o n s of ’ bn b i n d e r * t e r m o u t e r * t e l e r e b i n d a n d t e r m =

| T V a r of ’ fn

| TPi of ( tele , t e r m ) b i n d

| T L a m of ( tele , t e r m ) b i n d

| T A p p of t e r m * t e r m l i s t [ @ @ d e r i v i n g v i s i t o r s {

v a r i e t y = " map " ;

a n c e s t o r s = [ " B i n d i n g C o m b i n a t o r s . map " ] }]

(74)

Conclusion

(75)

Conclusion

Visitors arepowerful.

Visitor classes arepartial,composabledescriptions of operations.

Visitorscantraverseabstract syntax with binding.

I Syntax, binding forms, operations can beseparatelydescribed.

I Syntax and even binding forms can be described in adeclarativestyle.

I Open-ended, customizable approach.

Limitations:

I Macros are ugly.

I No proofs.

I Some operations may not fit the visitor framework;

I Some binding forms do not easily fit in the low-level framework or in the higher-level DSL, e.g., Unbound’sRec.

Références

Documents relatifs

2b corresponds to the theoretical spectrum for fBm’s with a Hurst exponent H = 0:58; the remarkable agreement observed with the WTMM data conrms the presence of long-range

Thierry Franchard, Remy Guebey, Julien Razafimahefa, Marcellin Andriantseheno, Harentsoaniaina Rasamoelina, Ronan Jambou.. To cite

Following a multi-stage process of problem solving, discussing the results and summarizing the conclu- sions, students have been asked about possible ways of introducing this

Her work concerns urban interactions (civility, incivility, and order in public spaces), and lies midway between urban ecology, the moral sociology of sociability behaviours and

Through these points, we hope to provoke thought about how explanation designers can better validate their design decisions via ExpG for explanation templates.. This is of

In VADA [21], all of format transformation, source selection, matching, mapping and data repair are informed by evidence in the form of the data context [20], instance values that

Visitors can traverse abstract syntax with binding. I Syntax, binding forms, operations are

I Can we insulate the end user from this complexity? We suggest distinguishing three principals..... Dealing with binding. Can a visitor traverse abstract syntax with