Lijsten in de -calculus Een lijst [E 1, E 2,..., E n ] kan in de -calculus voorgesteld worden als z.((z E 1 ) z.((z E 2 )... z.((z E n ) nil)...) met nil.

Slides:



Advertisements
Verwante presentaties
KINN 2010 •OOP •O Object •O Georiënteerd •P Programmeren.
Advertisements

Inleiding programmeren in C++ Life Science & Technology 1 maart Universiteit Leiden.
Programmeren met Alice
Hoofdstuk 8: Recursie.
PM zijn de Principia Mathematica. Deze vormen een formeel systeem voor de wiskunde. Ze zijn beschreven door A.N. Whitehead and B. Russell. Gödel bepaalt.
Deel I: Functionele Programmeertalen Hoofdstuk 4: Functioneel Programmeren.
Uitwerking tentamen Functioneel Programmeren 29 januari 2009.
Practica Computerlinguistiek Tekst en uitleg:
bewerkingen in programmeeromgevingen
Hogere-ordefuncties nEen lijst langs lopen en met elk element iets doen nEen lijst langs lopen en sommige elementen selecteren map filter.
Reductiemachine Functionele talen en dus de -calculus, worden vaak geïmplementeerd door een reductiemachine. De elementaire stap is een reductie, en de.
Hogere Wiskunde Complexe getallen college week 6
Automatisch Redeneren in de praktijk
Computervaardigheden Hoofdstuk 4 — Scripting (Let op: dit is enkel voor studenten Biologie.)
Hoofdstuk 6: Controle structuren
 - congruentie -regel:
Polymorf zoeken zoek :: (a  a  Bool)  [ (a, b) ]  a  b zoek eq [ ] x = ??? zoek eq ((a,b):ts) x | eq a x = b | otherwise = zoek eq ts x MayBe b No.
1 Datastructuren Sorteren: alleen of niet alleen vergelijkingen College 5.
Hogere-orde functies: herhaald patroon? Parametrizeer! product :: [Int]  Int product [ ]= product (x:xs)= 1 product xs x * and :: [Bool]  Bool and [
Functies op Proposities evalueer:: Bedeling  Prop  Bool tautologie:: Prop  Bool contradictie:: Prop  Bool equivalentie:: Prop  Prop  Bool vervulbaar::
Hoger-ordefuncties op lijsten nDoorloop een lijst en... map :: (a  b)  [a]  [b] filter :: (a  Bool)  [a]  [a] foldr :: (a  a  a)  a  [a]  a.
Parallelle Algoritmen String matching. 1 Beter algoritme patroonanalyse Bottleneck in eenvoudig algoritme: WITNESS(j) (j = kandidaat in eerste i-blok)
Assenstelsels en het plotten van Functies in LOGO
Deel I: Functionele Programmeertalen Hoofdstuk 5: Implementatie- technieken.
1 Prof. Dr. Martine De Cock academiejaar Lambdarekenen.
Functies als Getallen Jan Martin Jansen.
Numerieke Natuurkunde
Flow controle Keuzes maken. Het if-statement Soms moet code alleen in bepaalde situaties uit gevoerd worden Hiervoor heeft C de if-else constructie: if(voorwaarde1){
-calculus.
Functies definiëren nDoor combinatie van standaardfuncties fac :: Int  Int fac n = product [1..n] oneven :: Int  Bool oneven n = not (even n) negatief.
Char en String nCharéén letter uord ::Char  Int uchr ::Int  Char nString[Char] uwords :: String  [String] uunwords :: [String]  String ”hoi” ”CKI”
Hogere-ordefuncties nVoeg de elementen van een lijst samen nCombineer twee functies foldr :: (a  b  b)  b  [a]  b [a] (.) :: (b  c)  (a  b)  a.
Reguliere talen nReguliere grammatica: versimpelde Contextvrije grammatica nFinite-state Automaton: andere manier om een taal te beschrijven nReguliere.
Imperatief programmeren nProgramma bestaat uit nRunnen is opdrachten gegroepeerd in methoden één voor één uitvoeren te beginnen met main.
Functioneel Programmeren Daan Leijen. Wat gaan we doen? 3 fundamentele principes van computatie Equationeel redeneren IO-monad GUI's in Haskell (wxHaskell)
Hogere wiskunde Limieten college week 4
Hogeschool HZ Zeeland 19 augustus 2003augustus 2003 Data Structuren & Algoritmen Week 3.
P. 1 Vakgroep Informatietechnologie Structuur Deel II C++ Classes Namespaces Type casting Reference types Constructors en Destructors Memory Management.
Klik ergens op het witte deel van deze pagina om verder te gaan
Chris Pollentier 18 / 12 / 2002 De LOGO taalwereld.
Seminarie programmeren Het geheugen. Menu Memory 1.About 2.Mem Mgmt/del 3.Clear entries 4.clrAllLists 5.Archive 6.Unarchive 7.Reset 8.group →Sec mem.
Algoritme Inhoud: Definitie algoritme Recursieve algoritmes Opgaven
Samenvatting hst. 3 sec. 1-3 ( ) :: Parser a b  Parser a b  Parser a b ( ) :: Parser a (b  c)  Parser a b  Parser a c ( ) :: (b  c)  Parser a b.
Variabelen en berekeningen
Tircms03-p les 2 Hfdst 3,4 Meer operatoren Functies.
Tentamen vraag 1 Als L en M talen zijn, dan nL  M is gelijk aan { s  t | s  L, t  M } nL M is gelijk aan { s t | s  L, t  M } nL n is gelijk aan.
Tircms02-p les 3 Functies Strings Structuren. Functies 1. main() 2. { int k; k = 10 ; printf(“%d\n”,fac(k)); } 3. int fac(n) int n; 4. { int f; f= 1;
tircms02-p les 1 Operating Systems practicum
PROGRAMMEREN LOGISCH en FUNCTIONEEL Ik zeg wat ik denk!
Functioneel programmeren Een snelle herhaling…. Functie-definitie static int kwad (int x) { return x*x ; } kwad x = x * x Haskell kwad :: Int  Int.
Vervolg C Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology 1 Onderwerpen voor vandaag top-down decompositie Opdrachten:
Java Objectgeoriënteerd Programmeren in Java met BlueJ
Java Objectgeoriënteerd Programmeren in Java met BlueJ Hoofdstuk 7 Polymorfie en overerving © 2014, Gertjan Laan, versie 2.
Hoorcollege 1: efficiëntie en complexiteitsontwikkeling.
Hoorcollege 1: efficiëntie en complexiteitsontwikkeling.
Welkom! maandag 16 November 2015 Les B-2.
Variabelen. Wat zijn variabelen? In een programmeertaal zijn er “dingen” nodig die ervoor zorgen dat het programma informatie voor korte of langere tijd.
Codetuts Academy Les 6 Module 2a Php Fundamentals 1.
Les 3 - Operators Workshop Php Basic. ICT Academy Php Basic Content Operators Wiskundig Toewijzing Vergelijking.
Na de praktijk, de theorie.. Zoals een gehaktmolen 1.Je stopt er iets in. 2.Je hoeft niet te weten wat er binnenin gebeurt. 3.Het resultaat verschijnt.
IF() ELSE() LES 4: VOORWAARDEN. BOOL Een variabele die slechts 2 mogelijke waarden kan hebben: true(waar) of false(niet waar) duid je aan met bool bool.
De definitie van een object. Een object is een verzameling van eigenschappen en bewerkingen. Veel voorkomende objecten zijn: D (display) Gui (user interface)
Berekening van de Orde Van een Algoritme
Gameprogrammeren: Objecten en geheugen
Recursie in de wiskunde
Gameprogrammeren: Keuzeopdrachten
Gameprogrammeren: Expressies
Tinpro015b-les3 Hfdst 3,4 Meer operatoren Functies.
-calculus versus Scheme
Python – For loop + strings
Transcript van de presentatie:

Lijsten in de -calculus Een lijst [E 1, E 2,..., E n ] kan in de -calculus voorgesteld worden als z.((z E 1 ) z.((z E 2 )... z.((z E n ) nil)...) met nil een constant symbool dat de lege lijst voorstelt. Men neemt dan head == x.(x true), tail ==  x.(x false) en cons == x. y. z.((z x) y). Men moet dan geen extra notatie invoeren. Een beknopter alternatief bestaat erin de syntax uit te breiden met lijstexpressies van de vorm [E 1, E 2,..., E n ], met nieuwe symbolen voor combinatoren als head, tail en cons, en daar gepaste reductieregels voor te geven.

Lijsten: syntax ::= | … | ::= [ | [ ] ::=, | ] … ::= head | tail | cons … De syntax voor -expressies wordt als volgt uitgebreid: We kunnen nu expressies schrijven als bv. ( q.[p,q,r] A), ( x.[(x y),(y x)] B) of ( x.( y.[x,y] a) [b,c,d]), en we verwachten dat die reduceren tot respectievelijk [p,A,r], [(B y),(y B)] en [[b,c,d],a].

Lijsten: reductieregels (head [ ])  [ ] (head [E 1,...,E n ])  E 1 (tail [ ])  [ ] (tail [E 1,...,E n ])  [E 2,...,E n ] ((cons A) [ ])  [A] ((cons A) [E 1,...,E n ])  [A,E 1,...,E n ] (null [ ])  true (null [E 1,...,E n ])  false (1 [E 1,...,E n ])  E 1 (k [E 1,...,E n ])  ((pred k) [E 2,...,E n ])

Lijsten: reductieregels Ook de regels voor  -conversie en  -reductie moeten uitgebreid worden: {z/x} [E1,...,En]  [{z/x}E1,..., {z/x}En] ( x.[E1,...,En] Q)  [( x.E1 Q),..., ( x.En Q)]

Functies voor lijstmanipulatie: append append moet 2 lijsten samenvoegen: ( ( append [A 1, …, A m ] ) [B 1,…,B n ] ) = [A 1, …, A m,B 1,…,B n ] En dus, recursief, ((append x) y) = if (null x) then y else (((cons (head x)) (append (tail x)) y)) of in zuivere -notatie: append = x. y.(((null x) y) (((cons (head x)) (append (tail x)) y))) en met de Y-combinator: append = (Y f. x. y.(((null x) y) (((cons (head x)) (f (tail x) y))))

Functies voor lijstmanipulatie: map map past een fuctie toe op alle elementen van een lijst: ( (map f) [E 1,…,E n ] ) = [ (f E 1 ),…, (f E n ) ] En dus, recursief, ((map f) x) = if (null x) then [ ] else ((cons (f (head x))) ((map f) (tail x))) of in zuivere -notatie: map = m. x. y.(((null x) [ ]) ((cons (f (head x))) ((m f) (tail x)))) en met de Y-combinator: map = (Y m. x. y.(((null x) [ ]) ((cons (f (head x))) ((m f) (tail x)))))

Lijsten: tail recursion De som van de elementen van een lijst kan berekend worden met een polyadische uitbreiding van de gewone som - functie. In -calculus kan men werken met één argument, een lijst. Recursief: (sum x) = if (null x) then 0 else ((+ (head x)) (sum (tail x))) Deze vorm van recursie lijkt op die van map, maar er is een belangrijk verschil: daar kan men f toepassen op het eerste element zonder de rest van de recursie eerst te moeten uitwerken, maar hier kan de binaire + maar voor het eerst toegepast worden op de laatste 2 elementen van de lijst. Het eerste geval (zoals map dus) noemen we staart-recursie (tail recursion). Het tweede geval is minder wenselijk omdat er plaats moet voorzien worden om al de "pending" oproepen van + bij te houden. We kunnen wel een staart-recursieve definitie van sum geven:

Lijsten: tail recursion We voeren een accumulator a in: ((sum a) x) = if (null x) then a else ((sum ((+ a) (head x)) (tail x)). Het tweede argument van sum is nu (tail x), wat al korter is dan x. Op voorwaarde dat het eerste argument van sum wordt geëvalueerd voor het tweede, hebben we weer staart-recursie. Bij een oproep moet a natuurlijk geïnitializeerd worden op 0: ((sum 0) x) berekent de som van de elementen van x. Bij het rekenen met oneindige lijsten is staartrecursie uiteraard noodzakelijk.

Oneindige lijsten Oneindige, of op zijn minst "open ended" lijsten komen veel voor: getallen, woordenlijsten, streams,... zijn vaak geproduceerd door andere programma’s. Doorgeven ervan (bv. als functieargument) stelt mogelijk problemen: (f arg) met arg een oneindige lijst Oplossing: demand-driven evaluatie: onderbreek de evaluatie van een argument op het moment dat de toegepaste functie f verder uitgewerkt kan worden zonder het argument verder te evalueren. Komt overeen met normal order evaluatie, van bv. ((cons E1) ((cons E2)... ((cons En) nil)...). Dat lukt niet altijd: als f staat voor null, head, tail, dan kan het, maar niet als f staat voor, bv, sum.

Oneindige lijsten: zeros Stel dat we head willen toepassen op een oneindige lijst nullen Recursieve definitie van die lijst: zeros = ((cons 0) zeros) met de Y combinator: zeros = (Y z. ((cons 0) z)) wat inderdaad reduceert tot ( z. ((cons 0) z) (Y z. ((cons 0) z))) en dan tot ((cons 0) (Y z. ((cons 0) z))). Probleem: dit is niet van de vorm [E1,...,En] die we nodig hebben om de regel (head [E1,...,En])  E1 toe te passen

Lazy rules voor de lijstoperatoren Het probleem kan opgelost worden door nieuwe regels te introduceren voor de lijstoperatoren, zodat ze kunnen werken op slechts gedeeltelijk geëvalueerde lijsten. ((cons E) R)  [E,R (null [E,R )  false (head [E,R )  E (tail [E,R )  R (1 [E,R )  E (k [E,R )  ((pred k) R) voor k =2,3,... Deze regels stellen de lazy evaluatie van de lijstoperatoren voor. Het is nu geen probleem meer om bv. (5 zeros) te evalueren.

Strictness Een -expressie die een oneindige lijst voorstelt is, bekeken als functie, ongedefinieerd: de uitwerking ervan is oneindig. Toelaten dat een functie f, toegepast op een dergelijke expressie, toch een resultaat geeft, komt neer op het toelaten van niet-stricte functies: Een functie is strict als ze alleen gedefinieerd is wanneer al haar argumenten gedefinieerd zijn Voorbeelden van niet-stricte functies: conditionele expressie if C then A else B multiply (altijd 0 als eerste argument 0 is)

Voorbeelden Om een oneindige lijst te kunnen bouwen hebben we een functie nodig om telkens het volgende element te berekenen. De lijst van natuurlijke getallen ontstaat bv. door de functie succ te itereren. De lijst [ x, (f x), (f (f x)),... ] kan gedefinieerd worden als ((iterate f) x) = ((cons x) ((iterate f) (f x)) en dus expliciet als iterate = (Y i. f. x.((cons x) ((i f) (f x))). De lijst van alle natuurlijke getallen is dus numbers = ((iterate succ) 0). Analoog kan de lijst [ 1, 1, 2, 3, 5, 8, 13,... ] van Fibonacci getallen kan gedefinieerd worden als ((build x) y) = ((cons x) ((build y) ((+ x) y))) dus build = (Y b. x. y.((cons x) ((b y) ((+ x) y)))) en fibonacci = ((build 1) 1).

Zeef van Erathosthenes Hulpfunctie filter om veelvouden van n uit een lijst x te filteren: ((filter n) x) = if (null x) then [ ] else if (iszero ((mod (head x)) n)) then ((filter n) (tail x)) else (((cons (head x)) ((filter n) (tail x))) sieve kan nu gedefinieerd worden als (sieve x) = ((cons (head x)) (sieve ((filter (head x)) (tail x)))) en de lijst van priemgetallen kan dus uitgedrukt worden als: primes = (sieve ((iterate succ) 2)).

De getypeerde -calculus In deze versie van de -calculus wordt aan elke -expressie een type toegekend. Op die manier kan men de inconsistentie van de ongetypeerde calculus vermijden, en tegelijk het programmeren gemakkelijker maken door een type-checking systeem in te voeren.Types worden opgebouwd met type-constructoren, vertrekkende van een vaste set van ground types zoals int, boolean, real. Definitie (T1): de set Typ van beschikbare types is opgebouwd als volgt. (1) Alle ground types behoren tot Typ (2) Als  en  tot Typ behoren, dan    ook. Neem nu aan dat elke variabele een type heeft. Dan kunnen we voor elk type een aparte set van -expressies definiëren. Alleen -expressies die een welbepaald type hebben beschouwen we nog als geldig.

De getypeerde -calculus Neem nu aan dat elke variabele een type heeft. Dan kunnen we de set   van -expressies van type  definiëren als volgt: Definitie (T2): Voor elk type  is de set   van -expressies van type  gedefinieerd door: (1) Elke variabele van type  is in   (2) Als x tot   behoort en E behoort tot  , dan behoort x.E tot   (3) als P tot   behoort en Q behoort tot  , dan behoort (P Q) tot  . De set van alle getypeerde -expressies is de unie van alle  . Er zijn nu dus minder expressies: als P tot   behoort en Q behoort niet tot  , dan is (P Q) geen geldige expressie.

Uitbreiding: types voor lijsten Definitie T1 breiden we uit met de regel (3) Als  1,...,  n tot Typ behoren, dan ook [  1,...,  n ]. en Definitie T2 met twee regels: (4) Als de E i van type  i zijn, dan is [E 1,..., E n ] van type [  1,...,  n ]. (5) Als P van type [   1,...,   n ] is en Q van type , dan is (P Q) van type [  1,...,  n ]. Dus x.[E 1,..., E n ] is van type   [  1,...,  n ] en [ x.E 1,..., x.E n ] is van type [   1,...,   n ]. Applicatie van beide op een expressie van type  geeft een resultaat van type [  1,...,  n ].

 -reductie in getypeerde -calculus Een  -reductie ( x.P Q)  {Q/x}P is nu alleen mogelijk als x en Q hetzelfde type hebben. Als gevolg daarvan is  -reductie en dus ook gelijkheid consistent met de typering: -expressies die in mekaar omgezet kunnen worden hebben hetzelfde type.

Typechecking We hebben oneindig veel lijst-types, dus lijstoperatoren als head, tail, map enz. zijn overloaded. Ook een aantal constanten als + en * zijn overloaded. De regels van definitie T2 geven te weinig informatie om statische typechecking te kunnen doen voor, bv, overloaded functies als mult of add. Ze zeggen niets over relaties tussen types, zoals het feit dat een integer geïnterpreteerd kan worden als een real. Met behulp van de regels van T2 kunnen we aan type inferentie of typechecking doen: uitzoeken wat precies het type is van een expressie waarin overloaded symbolen voorkomen. Een expressie als ((mult 3.14) x) kan alleen het type real hebben, de informatie over het type van x is daarvoor niet nodig - dat moet real zijn. Het is helaas zeer moeilijk uit te maken voor welke variabelen het type zo kan bepaald worden.

Typechecking Het type van een -expressie hangt af van zijn componenten. Het bepalen van het type van een -expressie gebeurt dus "inside out", in tegenstelling tot normal order evaluatie. Om typechecking uit te voeren gaan we voor een expressie eerst een typedescriptor bouwen en die dan vereenvoudigen. Dit laatste is enigszins analoog aan het evalueren van de -expressie zelf. Er zijn wel verschillen, zoals het feit dat er niet in normal order kan geëvalueerd worden.

Typedescriptoren: syntax ::= | | | | | ::= int | real | bool ::=    ::= ( ) ::= [ ] | [ ::= ] | ::= + | - | * | / | | ≠ | ≤ | ≥ | head | tail | cons ::=   en  worden weggelaten als er geen dubbelzinnigheid is

Typedescriptoren Van essentieel belang is hier uiteraard de regel voor applicatie: ::= ( ) Het typechecking proces moet nagaan of de twee typedescriptoren in de applicatie compatibel zijn. Dat komt neer op de statische typecheck die men ook vindt in andere programmeertalen.

Toekenning van typedescriptoren TD{null} = gl  bool TD{x} =  als x een variabele van type  is TD{ x.P} = TD{x}  TD(P) TD{(P Q)} = (TD{P} TD{Q}) TD{[E 1,...,E n ]} = [ TD{E 1 },..., TD{E n } ] TD{  } =  voor elke typedescriptor  Door de laatste regel is de descriptor van een operator de operator zelf. Hij impliceert ook TD{ [ ] } = [ ]. gl is een generiek list-type. TD{0} TD{1} TD{succ} TD{and} = int... = int  int = bool   bool  bool  Definitie (T3): de typedescriptor TD{E} van een -expressie E is inductief bepaald door volgende regels.

Vereenvoudigen van typedescriptoren Dit gebeurt met volgende regels: (   ) = ([  1,...,  n ]  ) = (gl  [ ]) = (gl  [  1,...,  n ]) = ((+ int) int) =... ((bool  )  ) = (head [ ]) = (head [  1,...,  n ]) =  voor alle typedescriptoren  en  [  1,...,  n ] voor alle typedescriptoren  en  1,...,  n  voor alle typedescriptoren   voor alle typedescriptoren  en  1,...,  n int  [ ]  1

Vereenvoudigen van typedescriptoren (head [  1,...,  n ]  [  1,...,  n ]) = (tail [ ]) = (tail [  1,...,  n ]) = (tail gl) = ((cons  ) [ ]) = ((cons  ) [  1,...,  n ]) = (int [  1,...,  n ]) =  1  1 [ ] [  2,...,  n ] gl [  ] [ ,  1,...,  n ] [  1 ...   n ] en verder ook nog de gewone regels voor de unie 

Typechecking Deze regels vereisen soms heel wat pattern-matching: bv. de  bij een toepassing van de regel (   ) =  kan complex zijn. Indien er na de vereenvoudiging nog een applicatie-type blijft staan, dan is er een typefout opgetreden. Aangezien  verschilt van  voor elk type , is er geen zelf-applicatie mogelijk en kunnen we de Y combinator niet gebruiken. Wat wel gaat is voor elk type  een aparte combinator Y  invoeren, met reductieregel (Y  E)  (E (Y  E)) voor elke -expressie E, en type-inferentieregel (Y   ) =  voor elk type .

Voorbeeld De recursieve definitie van fact is: fact = n.(((iszero n) 1) ((mult n) (fact (pred n)))) Dit leidt tot de type-vergelijking  = (((int  bool int) int) (int  (int  int) int) (  (int  int int))) en na vereenvoudiging  = int  ((bool int) (int  int (  int))) Een oplossing is  = int  int, zoals verwacht. Het bestaan van een oplossing voor de type-vergelijking impliceert natuurlijk niet dat er een welgedefinieerde oplossing is voor de recursieve definitie: als we bv. in de definitie van fact de pred vervangen door succ, dan verandert er aan de typering niets.

Resultaten Wanneer we geen fixpuntcombinatoren invoeren zijn er in de getypeerde -calculus geen oneindige reducties, en dus geldt: Stelling: Elke getypeerde -expressie heeft een normaalvorm. (Doordat het aantal pijltjes  nooit stijgt tijdens de type- vereenvoudiging kan men bewijzen dat er in de getypeerde - calculus geen oneindige reducties voorkomen) We kunnen nu dus de normaalvorm zien als de betekenis of semantiek van een expressie.

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 worden, 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. 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)

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) let f = E 1 let g = E 2 eval E 3 wordt omgezet naar de -expressie ( f.( g.E 3 E 2 ) E 1 )

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, +, -,... renaming: {z/x}

Graph voorstelling: voorbeelden ((+ A) B) : : + A B

Graph voorstelling: voorbeelden [A 1, A 2,..., A n ],, [ ], A1A1 A2A2 AnAn...

Graph voorstelling: voorbeelden (( x. y.(x (y x)) 2) [E,F]) y :,, [ ] x 2 ::: #xy E F

Graph voorstelling: voorbeelden let fact = n.(((iszero n) 1) ((mult n) (fact (pred n)))) : : : : n fact : zero n : 1 * n pred : : n

Aangepaste regels Op een analoge manier kan men een reeks wederzijds recursieve definities en oneindige lijsten voorstellen. Om  -conversie te definiëren gebruikt men normaal inductie. Omdat de expressies willekeurig complex kunnen zijn kan men dat niet als een elementaire stap opvatten. Daarom elimineren we de  -conversie door ze "in te bouwen" in de  -reductie. Dat geeft aanleiding tot de volgende regels (de  -regels kunnen nog wat verder vereenvoudigd worden, zie”reductiemachine” )  -regel: x.E  z.( x.E z)  -regels: ( x.x Q)  Q ( x.y Q)  y als x en y verschillen ( x. x.E Q)  x.E ( x. y.E Q)  y.( x.E Q) als x en y verschillen, en x is niet vrij in E of y is niet vrij in Q ( x.(E 1 E 2 ) Q)  (( x.E 1 Q) ( x.E 2 Q))