De presentatie wordt gedownload. Even geduld aub

De presentatie wordt gedownload. Even geduld aub

Reductiemachine Functionele talen en dus de -calculus, worden vaak geïmplementeerd door een reductiemachine. De elementaire stap is een reductie, en de.

Verwante presentaties


Presentatie over: "Reductiemachine Functionele talen en dus de -calculus, worden vaak geïmplementeerd door een reductiemachine. De elementaire stap is een reductie, en de."— Transcript van de presentatie:

1 Reductiemachine Functionele talen en dus de -calculus, worden vaak geïmplementeerd door een reductiemachine. De elementaire stap is een reductie, en de "machinetaal" bestaat uit reductiestappen. In principe kan men die in hardware realiseren (LISP machine). Het uit te voeren programma is één -expressie, die stapsgewijs gereduceerd wordt tot normaalvorm. De expressie kan als een string symbolen voorgesteld worrden, maar dat vereist veel kopieerwerk. Daarom gebruiken moderne implementaties een graph voorstelling. Dat maakt wel het memory-management moeilijker, en heeft geleid tot de ontwikkeling van allerlei technieken voor garbage collection. In de vorm die we totnogtoe gezien hebben zijn  -conversie en  -reductie nog te complex om als één stap gezien te worden, we vervangen ze door meer elementaire stappen.

2 let en eval Om het programmeren te vergemakkelijken voert men "syntactic sugar" toe, zoals de mogelijkheid om hulpfuncties te definiëren (let) en om de evaluatie expliciet te starten (eval) staat voor: let f = E 1 let g = E 2 eval E 3 ( f.( g.E3 E2) E1)

3 Graph voorstelling Een -expressie wordt voorgesteld door haar parse tree, maar met extra pijlen die ervoor zorgen dat er cycli kunnen voorkomen. Dit betekent dat het originele programma gemakkelijk terug gereconstrueerd kan worden: in principe volstaat een depth-first doortocht van de parse tree. Soorten knopen: abstractie: x applicatie: : infix lijstconstructor:, lijst-einde of lege lijst: [ ] numerieke waarde: # variabele: x,y,z,... combinator: Y, true, false operator: head, tail, cons, +, -,... indirectie: @ renaming: {z/x}

4 Graph voorstelling: voorbeelden (( x. y.(x (y x)) 2) [E,F]) y :,, [ ] x 2 ::: xxy E F

5 Graph voorstelling: voorbeelden let fact = n.(((iszero n) 1) ((mult n) (fact (pred n)))) eval E : : : : n fact : iszero E : 1 * n pred : : nn

6 De regels Voor  -conversie en  -reductie gebruikten we totnogtoe volgende regels.  -regel: x.E  z.{z/x}E  -regel: ( x.E Q)  [Q/x]E Daarnaast zijn er de regels voor lijsten en constante symbolen. Omdat de expressies willekeurig complex kunnen zijn kan men het uitvoeren van die substituties niet als een elementaire stap opvatten. Daarom vervangen we deze regels door nieuwe, die wel elementaire stappen voorstellen. De regels voor lijsten worden iets sterker; we laten toe de applicatie van een lijst om te zetten in een lijst van applicaties - dit leidt tot de zgn.  -regels.

7 Aangepaste regels Voor  -conversie:  1 : {z/x}x  z  2 : {z/x}E  E als x niet vrij in E  3 : {z/x} y.E  y.{z/x}E als x, y en z verschillend  4 : {z/x}(E 1 E 2 )  ({z/x}E 1 {z/x}E 2 )  5 : {z/x}[E 1,...,E n ]  [{z/x}E 1,..., {z/x}E n ] De {z/x} wordt dus gewoon doorgeschoven naar binnen in de expressie.

8 Aangepaste regels Voor  -conversie:  1 : ( x.x Q)  Q  2 : ( x.E Q)  E als x niet vrij in E  3 : ( x. y.E Q)  z.( x.{z/y}E Q) als x verschillend van y, en z komt niet voor in E of in Q  4 : ( x.(E 1 E 2 ) Q)  (( x.E 1 Q) ( x.E 2 Q)) Voor  3 : we willen ( x. y.E Q)  [Q/x] y.E maar alleen als y "veilig" is. Dus beginnen we met y alvast te vervangen door een "verse" z. Omdat die uiteraard verschillend is van x kunnen we de x naar binnen schuiven, voorbij de z.

9 Aangepaste regels: de  - regels ( x.[E 1,...,E n ] Q)  [( x.E 1 Q),..., ( x.E n Q)] Voor lijsten vervangt men de regel Door de zgn.  -regels:  1 : ([E 1,...,E n ] Q)  [(E 1 Q),..., (E n Q)] en  2 : x.[E 1,...,E n ]  [ x.E 1,..., x.E n ] Deze regels, samen met die voor de combinatoren en operatoren, kunnen nu omgezet worden naar elementaire stappen voor de reductiemachine.

10 Stappen:  -regels {z/x}x  z {z/x}E  E als x niet vrij in E {z/x} y.E  y.{z/x} E als x  y  z y z/x x z x E @ E y E y E   

11 Stappen:  -regels {z/x}(E 1 E 2 )  ({z/x}E 1 {z/x}E 2 ) {z/x}[E 1,...,E n ]  [{z/x}E 1,...,{z/x}E n ] z/x : E1E1 E2E2 : : E1E1 E2E2,, A B, A B  

12 Stappen:  -regels  1 : ( x.x Q)  Q x x Q :  x x Q @  2 : ( x.E Q)  E als x niet vrij in E x Q : E x Q @ E 

13 Stappen:  -regels  3 : ( x. y.E Q)  z.( x.{z/y}E Q) als x en y verschillen, en z is vers: noch vrij, noch gebonden in (E Q) y x Q : E Q y x E z x z/y : 

14 Stappen:  -regels  4 : ( x.((E 1 E 2 ) Q)  (( x.E 1 Q) ( x.E 2 Q))  x Q : : E1E1 E2E2 x Q : : E1E1 E2E2 : x x :

15 Stappen:  -regels  1 : ([E 1,...,E n ] Q)  [(E 1 Q),..., (E n Q)] , C : A B, C, A B : :

16 Stappen:  -regels  2 : x.[E 1,...,E n ]  [ x.E 1,..., x.E n ] , A B x, A B x x,

17 In plaats van de cyclische representatie te gebruiken, kunnen we ook de Y-combinator expliciet voorstellen, en volgende regel gebruiken. Het gebruik van de cyclische representatie van recursieve functies blijkt gewoonlijk efficiënter te zijn. Y combinator  : Y F : Y F :

18 Opmerkingen Ook voor de combinators null, +, head,... zijn er uiteraard dergelijke operaties. De operaties behouden altijd de knopen aan de linkerkant (er kunnen nog andere pijlen zijn naar die knopen) en wijzigen enkel van de root het label. Op die manier is het duidelijk hoe het vervangen deel van de graph vasthangt aan de rest. De operaties voeren nooit nieuwe cycli in; de enige cycli zijn die veroorzaakt door recursieve definities.

19 Implementatie Om de knopen voor te stellen gebruikt men bv. 4 velden : ( code, op 1, op 2, marker) (marker voor de garbage collector). Het herkennen van een patroon in een graph is in het algemeen een moeilijk probleem. Gelukkig zijn de te herkennen patronen hier erg klein. Om een  -redex te vinden: gebruik een depth-first traversal om het volgende patroon op te sporen: : x N1N1 N2N2 N3N3

20 Implementatie Als N 2 geen abstractieknoop is, dan is N 1 niet de root van een  -redex. Anders, zoek een vrije occurence van x in de boom onder N 3. Als er geen te vinden is, dan hebben we een  2 -redex. Als er wel een gevonden wordt, dan bepaalt het veld code van N 3 of we een redex voor  1,  3 of  4 herkennen. Als N 3 noch een variable-, noch een abstractie-, noch een applicatieknoop is, dan is N 1 niet de root van een  -redex. Het zoeken naar een vrije occurence van x voor herkennen van een  2 - redex kan uitgevoerd worden in een depth-first doortocht. Ook voor  -redexen kunnen we volstaan met het onderzoeken van 2 knopen, met weer een extra test voor  2.

21 Evaluatie-orde Doordat we nu andere regels hebben is normal order evaluatie niet meer helemaal wat we nodig hebben: bv (( x. y.E P) Q)  (  3 ) ( z.( x.{z/y}E P) Q)  (  4 ) (( z. x.{z/y}E Q) ( z.P Q))  (  3 ) ( v.( z.{v/x}{z/y}E Q) ( z.P Q))  (  4 ) (( v. z.{v/x}{z/y}E ( z.P Q)) ( v.Q ( z.P Q))) ... Afspraak: na  3 verder gaan met het deel na de nieuwe (meest linkse).

22 Evaluatie-orde Eager, applivative order: argumenten eerst. Demand - driven: argumenten pas evalueren als nodig. Lazy: ook de argumenten maar partieel evalueren als dat volstaat. Normal order: meest linkse redex. In ons systeem komt dat overeen met lazy. Lazy evaluatie is niet altijd efficiënt: ( x.((+ x)(pred x)) ((* 5) (succ 3)))  (  4 ) met Q = ((* 5) (succ 3)) (( x.(+ x) Q) ( x.(pred x) Q))  (  4 ) ((( x.+ Q) ( x.x Q)) ( x.(pred x) Q))  (  1,  2 ) ((+ ((* 5) (succ 3))) ( x.(pred x) Q))  (regels voor *, succ) ((+ 20) ( x.(pred x) Q)) ... en Q moet opnieuw geëvalueerd worden.

23 Graph reductie De boom van Q = ((* 5) (succ 3)) wordt niet gedupliceerd: 3 : :: : : : : 5 pred x + x * succ x  44

24 Graph reductie 3 : :: : : : : 5 pred x + x * succ x : : x x

25 Opmerkingen Deze reductiemachine kan uiteraard geperfectioneerd worden, bv, door parallellisme te gebruiken. Moderne implementaties halen de efficiëntie van een behoorlijke C compiler. I/O, of andere neveneffecten, kan men inbouwen door gebruik te maken van monads: interpreteer sommige symbolen m als acties; en bekijk paren (m,a), met m een actie en a een waarde. Er is een sequencing operatie >>= van type m a  ( a  m b )  m b Informeel: een actie die een a oplevert kan samengesteld worden met een functie die op basis van een a een actie geeft die een b oplevert. Het resultaat is een actie die een b oplevert.

26 Unificatie In Haskell wordt pattern matching gebruikt in de definitie van functies, bv. in qsort: matching qsort [x:xs] met [3,2,4,1,5] resulteert in de binding van x aan 3 en van xs aan [2,4,1,5]. Ook by typechecking komt een dergelijke situatie voor: als men een functie f wil toepassen op een argument arg, dan moet de typedescriptor van f van de vorm td 1  td 2 zijn, en als arg typedescriptor td arg heeft, dan moeten td 1 en td arg "gelijk gemaakt" kunnen worden, door vereenvoudigingen, maar ook door de vervanging van typevariabelen door meer concrete typedescriptoren. Dit "gelijk maken" (en tegelijk variabelen binden) noemt men unificatie Ook in logische talen speelt unificatie een belangrijke rol.

27 Unificatie qsort(cons(x, xs)) en cons(3, cons(2, cons(4, cons(1, cons(5, [ ]))))) (in gewone mathematische notatie) resultaat: x = 3 xs = cons(2, cons(4, cons(1, cons(5, [ ])))) mult(add(4, 5), minus(y)) en mult(add(x,y), z) resultaat: x = 4 y = 5 z = minus(5) mult(add(4, 5), minus(y)) en mult(add(x,y), 8) resultaat: fail

28 Unificatie: algemeen Gegeven: twee termen, T 1 en T 2, opgebouwd uit - variabelen - constanten - functie-applicaties ("Functoren", in logisch programmeren) Gevraagd: een meest algemene unifier (most general unifier, MGU) voor T 1 en T 2 unifier: een substitutie  (afbeelding van de variabelen naar de termen) die voldoet aan  ( T 1 ) =  ( T 2 ) most general unifier: een unifier met de eigenschap dat, voor elke andere unifier  ', geldt dat  '( T 1 ) een instantie is van  ( T 1 ), m.a.w. er is een substitutie  die van  ( T 1 )  '( T 1 ) maakt:  (  ( T 1 )) =  '( T 1 ) (er geldt dan ook  (  ( T 2 )) =  '( T 2 ) natuurlijk).

29 Unificatie: algoritme van Robinson MGU = { }; WS = { (T 1, T 2 ) } repeat verwijder een paar (R 1, R 2 ) uit WS; case R 1 en R 2 zijn twee identieke variabelen of constanten: skip; R 1 is een variabele die niet voorkomt in R 2 : vervang, overal in WS en MGU, R 1 door R 2 ; voeg (R 1, R 2 ) toe aan MGU; R 2 is een variabele die niet voorkomt in R 1 : vervang, overal in WS en MGU, R 1 door R 2 ; voeg (R 1, R 2 ) toe aan MGU; R 1 = f(y 1,...,y n ) en R 2 = f(z 1,...,z n ): voeg {(y 1,z 1 ),...,(y n,z n )} toe aan WS otherwise return(fail) end case until WS = { }


Download ppt "Reductiemachine Functionele talen en dus de -calculus, worden vaak geïmplementeerd door een reductiemachine. De elementaire stap is een reductie, en de."

Verwante presentaties


Ads door Google