Peatükk 9 Andmestruktuurid puhtas λ-arvutuses
Eelnevalt nägime, kuidas arvutada konstantidega λ-arvutuses, kus konstantideks võtsime tõeväärtused, täisarvud, paarid ja listid. Nüüd vaatame, kuidas defineerida tõeväärtused, naturaalarvud, paarid ja listid kasutades puhast λ-arvutust. See tähendab, et teoreetilises lähenemises võime konstante ja δ-reduktsioone ignoreerida.
Definitsioonideks valime kombinaatorid: ilma vabade muutujateta termid, mis on normaalkujul. Nii käituvad meie definitsioonid sarnaselt konstantidele — ei tekita juurde vabu muutujaid ega redutseeru selliselt, et me neid ära ei tunne.
Tegelikult on võimalik kõik abstraktsioonid kirjeldada S, K ja I kombinaatoritega.
|
| | I | := λ x. x | | | | | | | | | |
|
K | := λ x y. x | | | | | | | | | |
|
S | := λ f g x. f x (g x)
| | | | | | | | | |
|
Tõeväärtuste spetsifikatsiooniks võtame tõeväärtuste funktsioonide δ-reduktsioonid, leiame konstantidele vastavad λ-termid ja näitame, et δ-reduktsiooni asemel saame teha β-reduktsioone ja saada sama tulemuse.
9.1 Tõeväärtuste implementatsioon
Tõeväärtuste operatsioonid on spetsifitseeritud järgnevalt.
|
| | not true | →δ false | | | | | | | | | |
|
not false | →δ true | | | | | | | | | |
|
cond true e1 e2 | →δ e1 | | | | | | | | | |
|
cond false e1 e2 | →δ e2
| | | | | | | | | |
|
Sobivate definitsioonide leidmiseks kasutame järgnevat strateegiat: väärtuseks võtame vastava väärtuse mustrisobituse operatsiooni. Tõeväärtuse true mustrisobitus ehk tingimuslause võtab kaks parameetrit, e1 ja e2, ning tagastab e1. Seega võtame true := λ x y. x. Sarnase argumentatsiooniga võtame false := λ x y. y. Muud operatsioonid saame programmeerida kasutades teadmist, et tõeväärtused on nendele vastavad tingimuslaused.
|
| | not | := λ t. t false true | | | | | | | | | |
|
cond | := λ t. t
| | | | | | | | | |
|
Saame näidata, et δ-reduktsioonile vastab mitmesammuline β-reduktsioon.
| not true | = | (λ t. t false true) true |
| | →β | true false true |
| | = | (λ x. λ y. x) false true |
| | →β | (λ y. false) true |
| | →β | false
|
|
| not false | = | (λ t. t false true) false |
| | →β | false false true |
| | = | (λ x. λ y. y) false true |
| | →β | (λ y. y) true |
| | →β | true
|
|
| cond true e1 e2 | = | (λ t. t) true e1 e2 |
| | →β | true e1 e2 |
| | = | (λ x. λ y. x) e1 e2 |
| | →β | (λ y. e1) e2 |
| | →β | e1
|
|
| cond false e1 e2 | = | (λ t. t) false e1 e2 |
| | →β | false e1 e2 |
| | = | (λ x. λ y. y) e1 e2 |
| | →β | (λ y. y) e2 |
| | →β | e2
|
|
9.2 Paaride implementatsioon
Paaride operatsioonid on spetsifitseeritud järgnevalt.
|
| | fst (pair e1 e2) →δ e1 | | | | | | | | | | |
|
snd (pair e1 e2) →δ e2
| | | | | | | | | | |
|
Definitsioonide leidmise strateegia on sama mis tõeväärtuste puhul — leiame mustrisobitusele vastava termi. Idrises saab paaride mustrisobitust teostada avaldisega match MkPair e_1 e_2 with MkPair x y => p. Seega λ-arvutuses võime võtta näiteks pair = λ e1 e2 p. p e1 e2. Ehk siis paari komponendid antakse ainukesele harule edasi eraldi parameetritena. Siis fst ja snd saame impmeneteerida kasutades mustrisobitus järgnevalt.
|
| | fst | := λ p. p true | | | | | | | | | |
|
snd | := λ p. p false
| | | | | | | | | |
|
Nüüd saame näidata definitsioonide vastavust spetsifikatsioonile.
| fst (pair e1 e2) | = | (λ p. p true) (pair e1 e2) |
| | →β | (pair e1 e2) true |
| | = | (λ e1 e2 p. p e1 e2) e1 e2 true |
| | ↠β | true e1 e2 |
| | = | (λ x y. x) e1 e2 |
| | ↠β | e1
|
|
| snd (pair e1 e2) | = | (λ p. p false) (pair e1 e2) |
| | →β | (pair e1 e2) false |
| | = | (λ e1 e2 p. p e1 e2) e1 e2 false |
| | ↠β | false e1 e2 |
| | = | (λ x y. y) e1 e2 |
| | ↠β | e2
|
|
9.3 Naturaalarvud
Natutaalarvude kohta nõuame, et succ , pred , iszero , add ja mul arvutaks vastavalt järgmise arvu, eelmise arvu, arvu võrdumise nulliga, liitmise ja korrutamise.
Esmalt püüame ehitada nii, et nulli esitab identsusfunktsioon λ x. x ja nullist suuremad arve paarid, mille esimene komponent on false ja teine on ühe võrra väiksem number.
Nii on arvude struktuur sarnane Idrise struktuurile aga lisatud on false komponendid.
Sellist konstruktsiooni nimetatakse standardnumbriteks.
|
| | ⌜ 0 ⌝ | := λ x. x | | | | | | | | | |
|
⌜ n+1 ⌝ | := pair false ⌜ n ⌝ | | | | | | | | | |
|
succ | := λ n. pair false n | | | | | | | | | |
|
pred | := snd | | | | | | | | | |
|
iszero | := fst
| | | | | | | | | |
|
Saame näidata, et succ , pred ja iszero töötavad korrektselt. Näeme, et pred töötab vaid nullist suuremate arvude korral.
| succ ⌜ n ⌝ | = | (λ n. pair false n) ⌜ n ⌝ |
| | →β | pair false ⌜ n ⌝ |
| | = | ⌜ n+1 ⌝
|
|
| pred ⌜ n+1 ⌝ | = | (λ p. p false) (pair false ⌜ n ⌝ ) |
| | →β | pair false ⌜ n ⌝ false |
| | = | (λ e1 e2 p. p e1 e2) false ⌜ n ⌝ false |
| | ↠β | false false ⌜ n ⌝ |
| | = | (λ x y. y) false ⌜ n ⌝ |
| | ↠β | ⌜ n ⌝
|
|
| pred ⌜ 0 ⌝ | = | (λ p. p false) (λ x. x) |
| | →β | (λ x. x) false |
| | →β | false
|
|
| iszero ⌜ 0 ⌝ | = | (λ p. p true) (λ x. x) |
| | →β | (λ x. x) true |
| | →β | true
|
|
| iszero ⌜ n+1 ⌝ | = | (λ p. p true) (pair false ⌜ n ⌝) |
| | →β | pair false ⌜ n ⌝ true |
| | = | (λ e1 e2 p. p e1 e2) false ⌜ n ⌝ true |
| | ↠β | true false ⌜ n ⌝ |
| | →β | false
|
|
Kui makrode defineerimisel oleks rekursioon lubatud, saaks standardnumbrite liitmise defineerida kui add := λ x y. cond (iszero x) y (add (pred x)(succ y)). Hiljem, peatükis 9.5, näeme ühte võimalust, kuidas rekursiooniga hakkama saada. Enne aga vaatame ühte alternatiivset lähenemist — Churchi numbreid.
Numbrite defineerimiseks kasutame funktsiooni termide astendamise notatsiooni. Termide E, E∈ Λ jaoks En E′ rakendab funktsiooni E n-korda, alustades argumendist E′. Ehk E0 E′ = E′, E1 E′ = E E′, E2 E′ = E (E E′) , E3 E′ = E (E (E E′)) jne. Nüüd saame defineerida Churchi numbrid.
|
| | := λ f x. fn x | | | | | | | | | |
|
succ | := λ n. λ f x. f (n f x) | | | | | | | | | |
|
iszero | := λ n. n (λ x. false) true
| | | | | | | | | |
|
Churchi numbrite intuitsioon on, et arv n tähistab mingi valitud operatsiooni n-kordset tegemist — arv vastab sellele, mitu iteratsiooni tuleb teha. Arvule ühe lisamine tähendab ühe iteratsiooni lisamist. Nulliga võrdumist saab kontrollida nii, et algseisuks võetakse true ja tsüklis muudetakse see false -ks; nulli iteratsiooni puhul jääb seisundiks true ja rohkemate iteratsioonide puhul on tulemus false . Vaata formaalseid β-reduktsioone.
| = | (λ n. λ f x. f (n f x)) (λ f x. fn x) |
| | →β | λ f x. f ((λ f x. fn x) f x) |
| | ↠β | λ f x. f (fn x) |
| | = | λ f x. fn+1 x |
| | = | |
|
| = | (λ n. n (λ x. false) true) (λ f x. x) |
| | →β | (λ f x. x) (λ x. false) true |
| | ↠β | true
|
|
| = | (λ n. n (λ x. false) true) (λ f x. f (fn x)) |
| | →β | (λ f x. f (fn x)) (λ x. false) true |
| | ↠β | (λ x. false) ((λ x. false)n true) |
| | →β | false
|
|
Liitmise, korrutamise ja isegi astendamise saame defineerida järgnevalt. Pane tähele, et astendamise definitsiooni saaks kirjutada veel lühemalt: exp = λ m n. n m.
|
| | add | := λ m n. λ f x. m f (n f x) | | | | | | | | | |
|
mul | := λ m n. λ f x. m (n f) x | | | | | | | | | |
|
exp | := λ m n. λ f x. n m f x
| | | | | | | | | |
|
Vaatame, kuidas term add m n β-redutseerub naturaalarvude m ja n summaks. Intuitiivselt, kõigepealt tehakse n iteratsiooni ja seejärel veel m iteratsiooni. Korrutamise korrektsuse verifitseerimiseks peame veenduma, et (λ x. fn x )m x on tõesti sama kui fmn x. Ehk, intuitiivselt m korda tehakse n iteratsiooni.
| = | | (λ m n. λ f x. m f (n f x)) | | | |
|
| | ↠β | |
| | = | λ f x. (λ f x. fm x) f ((λ f x. fn x) f x) |
| | ↠β | λ f x. fm (fn x) |
| | = | |
|
| = | | (λ m n. λ f x. m (n f) x) | | | |
|
| | ↠β | |
| | = | | λ f x. (λ f x. fm x ) ( | | f) x |
|
| | ↠β | |
| | = | λ f x. ((λ f x. fn x ) f)m x |
| | →β | λ f x. (λ x. fn x )m x |
| | ↠β | λ f x. fmn x |
| | = | |
|
Churchi numbrite puhul on keeruliseks ülesandeks hoopis ühe lahutamine. Intuitiivselt, kui meil on arv n ja me saame teha n iteratsiooni aga soovime teha n−1 iteratsiooni.
Selle probleemile on kaks standardset lahendust. Esiteks vaatame lahendust, kus meil intuitiivselt on iteratsioonis lisamuutuja — tõeväärtus, mis ütleb, kas me oleme juba ühe maha lahutanud. Vajame abifunktsiooni, mis käituks järgnevalt.
| prefn f (true,x) | ↠ | (false,x) |
| prefn f (false,x) | ↠ | (false,f x) |
| (prefn f)n (false,x) | ↠ | (false,fn x)
|
|
Sellist spetsifikatsiooni rahuldab järgmine definitsioon.
|
| | prefn := λ f p. (false,(cond (fst p) (snd p) (f (snd p))))
| | | | | | | | | | |
|
| prefn f (true,x) | = | (λ f p. (false,(cond (fst p) (snd p) (f (snd p))))) f (true,x) |
| | ↠β | (false,(cond (fst (true,x)) (snd (true,x)) (f (snd (true,x))))) |
| | ↠β | (false,(cond true (snd (true,x)) (f (snd (true,x))))) |
| | ↠β | (false,snd (true,x)) |
| | ↠β | (false, x)
|
|
| prefn f (false,x) | = | (λ f p. (false,(cond (fst p) (snd p) (f (snd p))))) f (false,x) |
| | ↠β | (false,(cond (fst (false,x)) (snd (false,x)) (f (snd (false,x))))) |
| | ↠β | (false,(cond false (snd (false,x)) (f (snd (false,x))))) |
| | ↠β | (false, f (snd (false,x))) |
| | ↠β | (false, f x)
|
|
Reduktsiooni (prefn f)n (false,x) ↠ (false,fn x) tõestame induktsiooniga üle naturaalarvu n. Vaatame baasjuhtu n=0 ja induktsiooni sammu n=n′+1.
| (prefn f)0 (false,x) | = | (false,x) |
| | = | (false, f0 x)
|
|
| (prefn f)n′+1 (false,x) | = | (prefn f)n′ (prefn f (false,x)) |
| | ↠β | (prefn f)n′ (false, f x) |
| | ↠β | (false, fn′ (f x)) |
| | = | (false, fn′+1 x)
|
|
Siis saame defineerida eelmise arvu leidmise operaatori pred .
|
| | pred := λ n. λ f x. snd (n (prefn f) (true,x))
| | | | | | | | | | |
|
| = | | (λ n. λ f x. snd (n (prefn f) (true,x))) | |
|
| | ↠β | | λ f x. snd ( | | (prefn f) (true,x)) |
|
| | = | λ f x. snd ((λ f x. f0 x) (prefn f) (true,x)) |
| | ↠β | λ f x. snd (true,x) |
| | ↠β | λ f x. x |
| | = | λ f x. f0 x
|
|
| = | | (λ n. λ f x. snd (n (prefn f) (true,x))) | |
|
| | ↠β | | λ f x. snd ( | | (prefn f) (true,x)) |
|
| | = | λ f x. snd ((λ f x. fn+1 x) (prefn f) (true,x)) |
| | ↠β | λ f x. snd ((prefn f)n+1 (true,x)) |
| | = | λ f x. snd ((prefn f)n (prefn f (true,x))) |
| | ↠β | λ f x. snd ((prefn f)n (false,x)) |
| | ↠β | λ f x. snd (false,fn x)) |
| | ↠β | λ f x. fn x |
| | = | λ f x. fn x
|
|
Seega oleme andnud ühe naturaalarvude implementatsiooni kasutades paari ja tõeväärtust. Teine variant on implementeerida viivitus naturaalarvude paariga, mille mõlemad komponendid on alguses nullid. Iga iteratsioon kopeerib paari teise komponendi esimeseks ja suurendab teiset komponenti ühe võrra — nii on paari esimene komponent alati peale esimest iteratsiooni ühe võrra väiksem. Peale iteratsioone tagastatakse paari esimene komponent.
|
| | f | := λ p. pair (snd p) (succ (snd p)) | | | | | | | | | |
|
pred | | := λ n. fst (n f (pair | | | | ))
|
| | | | | | | | | |
|
Esmalt tõestamie induktsiooniga, et f-i n-kordsel rakendamisel paarile pair m m+1 on tulemuseks (pair m+n m+n+1). Induktsiooni baas kehtib triviaalselt kuna f0 (pair m m+1) = pair m m+1. Induktsiooni sammu kehtivust tõestab järgnev reduktsioon.
|
| | fn+1 | | | | | | | | | | |
| | | = (λ p. pair (snd p) (succ (snd p))) (fn (pair | | | | )) |
| | | | | | | | | |
| | | →β pair (snd (fn (pair | | | | ))) (succ (snd (fn (pair | | | | )))) |
| | | | | | | | | |
| | | →β pair (snd (pair | | | | )) (succ (snd (pair | | | | ))) |
| | | | | | | | | |
| | | | | | | | | | | |
| | | | | | | | | | | |
|
Nüüd saame hõlpsasti näidata, et pred 0 redutseerub väärtuseks 0 ja pred n+1 redutseerub väärtuseks n.
9.4 Listid
Listide kohta on jägnevad δ-reduktsioonireegild.
|
| | null nil | →δ true | | | | | | | | | |
|
null (cons e1 e2) | →δ false | | | | | | | | | |
|
hd (cons e1 e2) | →δ e1 | | | | | | | | | |
|
tl nil | →δ nil | | | | | | | | | |
|
tl (cons e1 e2) | →δ e2
| | | | | | | | | |
|
Sarnaselt naturaalarvudele, on siin võimalik kaks lähenemist. Esiteks võime lähtuda listi mingist fold-funktsioonist ja implementeerida null, hd ja tl kasutades seda fold-i. Teine võimalus oleks kasutada paare ja tõeväärtueseid — teades ette, et fold-i puudumisel on paljude funktsioonide implementeerimiseks vaja rekursioon.
Vaatame esmalt põgusalt listide implementatsiooni, mis on tuletatud listide foldr funktsioonist.
|
| | nil | := λ f b. b | | | | | | | | | |
|
cons | := λ x l. λ f b. f x (l f b)
| | | | | | | | | |
|
Nüüd saame implementeerida konstandid null ja hd.
|
| | null | := λ l. l (λ y z. false) true | | | | | | | | | |
|
hd | := λ l. l (λ y z. y) I
| | | | | | | | | |
|
| null nil | = | (λ l. l (λ y z. false) true) nil |
| | →β | nil (λ y z. false) true |
| | = | (λ f b. b) (λ y z. false) true |
| | ↠β | true
|
|
| null (cons x l) | = | (λ l. l (λ y z. false) true) (cons x l) |
| | →β | cons x l (λ y z. false) true |
| | = | (λ x l. λ f b. f x (l f b)) x l (λ y z. false) true |
| | ↠β | (λ y z. false) x (l (λ y z. false) true) |
| | ↠β | false
|
|
| hd (cons x l) | = | (λ l. l (λ y z. y) I) (cons x l) |
| | →β | cons x l (λ y z. y) I |
| | = | (λ x l. λ f b. f x (l f b)) x l (λ y z. y) I |
| | ↠β | (λ y z. y) x (l (λ y z. y) I) |
| | ↠β | x
|
|
Listi saba leidmine kasutades fold funktsioone on võimalik aga parajalt tülikas. Definitsioonid tulevad pikad ja korrektsuse näitamine võtab palju samme. Seetõttu piirdume siin Idrise koodiga, mis arvutavad listi saba kasutade foldr või foldl.
| 1tl1 : List a -> List a
2tl1 l = snd (foldl f (True,[]) l) where
3 f : (Bool, List a) -> a -> (Bool, List a)
4 f (True ,r) x = (False, r)
5 f (False,r) x = (False, r++[x])
6
7tl2 : List a -> List a
8tl2 l = snd (foldr f (pred (length l), []) l) where
9 f : a -> (Nat, List a) -> (Nat, List a)
10 f x (0, r) = (0, r)
11 f x (S n, r) = (n, x::r) |
Teine võimalus listifunktsioone defineerida on läbi paaride ja tõeväärtuste.
|
| | nil | := λ z. z | | | | | | | | | |
|
cons | := λ x y. pair false (pair x y) | | | | | | | | | |
|
null | := λ z. z true | | | | | | | | | |
|
hd | := λ z. fst (snd z) | | | | | | | | | |
|
tl | := λ z. snd (snd z )
| | | | | | | | | |
|
Nüüd saame näidata, et meie definitsioonid vastavad spetsifikatsioonile kasutades β-reduktsiooni.
| null nil | = | (λ z. z true) nil |
| | →β | nil true |
| | = | (λ z. z) true |
| | ↠β | true
|
|
| null (cons x l) | = | (λ z. z true ) (cons x l) |
| | →β | cons x l true |
| | = | (λ x y. pair false (pair x y)) x l true |
| | ↠β | pair false (pair x l) true |
| | ↠β | true false (pair x l) |
| | ↠β | false
|
|
| hd (cons x l) | = | (λ z. fst (snd z)) (cons x l) |
| | →β | fst (snd (cons x l)) |
| | = | fst (snd ((λ x y. pair false (pair x y)) x l)) |
| | ↠β | fst (snd (pair false (pair x l))) |
| | ↠β | fst (pair x l) |
| | ↠β | x
|
|
| tl (cons x l) | = | (λ z. snd (snd z)) (cons x l) |
| | →β | snd (snd (cons x l)) |
| | = | snd (snd ((λ x y. pair false (pair x y)) x l)) |
| | ↠β | snd (snd (pair false (pair x l))) |
| | ↠β | snd (pair x l) |
| | ↠β | l
|
|
Sellised definitsioonid ei võimalda meil aga defineerida rekursiivset foldr funktsiooni. Järgmisena vaatamegi, kuidas toetada rekursiivset käitumist.
9.5 Püsipunktid
Termi M nimetatakse püsipunktikombinaatoriks kui kehtib
Tuntuim püsipunktikombinaator on Haskell Curry “paradoksaalne” kombinaator
| Y := λf. (λx. f (x x)) (λx. f (x x)).
|
Saame näidata, et Y on püsipunktikombinaator.
|
| | Y e | | →β | | (λx. e (x x)) (λx. e (x x)) |
|
|
| | | | | | | | | |
| | →β e ((λx. e (x x)) (λx. e (x x))) | | | | | | | | | |
| | | | | | | | | | | |
|
Pane tähele, et tõestuse viimase sammuna tuleb β-ekspansioon, mitte β-reduktsioon. Seetõttu on mõnevõrra raskendatud Y e-ks ekspandeerutava termi äratundmine suurema termi sees — kui meil oleks mingi konkreetne term e. Seetõttu võib olla kasulik kasutada hoopis “tugevat” püsipunkti kombinaatorit Θ.
| Θ := (λ x y. y (x x y)) (λ x y. y (x x y))
|
Kombinaatori Θ kohta saame tõestada tugevama väite, et Θ e →β e (Θ e).
|
| | Θ e | | →β | | (λx y. y (x x y)) (λx y. y (x x y)) |
|
| e |
| | | | | | | | | |
| | | →β | | (λy. y ((λx y. y (x x y)) (λx y. y (x x y)) y)) e |
|
|
| | | | | | | | | |
| | →β e ((λx y. y (x x y)) (λx y. y (x x y)) e) | | | | | | | | | |
| | = e (Θ e)
| | | | | | | | | |
|
Püsipunktikombinaatoreid saab kasutada rekursiivsete funktsioonide defineerimiseks. Võtame näiteks standardnumbrite (naturaalarvude) liitmise. Rekursiivse väljakutse jaoks lisame definitsiooni esimese parameetri ja rakendame funktsiooni püsipunktikombinaatorile.
|
add := Y (λf x y. cond (iszero x) y (f (pred x)(succ y)))
|
Tõestame näiteks ka liitmise korrektsust, s.t, et add m n redutseerub avaldiseks m+n. Tõestuseks kasutame induktsiooni ja alustame baasjuhust m=0, kus kasutame add-i definitsiooni järel püsipunktikombinaatori võrdust Y f =β f (Y f), teadmist iszero 0 ↠β true ja cond true e1 e2 ↠β e1.
|
| | | =
Y (λf x y. cond (iszero x) y (f (pred x)(succ y))) | | | |
| | | | | | | | | |
| | | =β λf x y. cond (iszero x) y (f (pred x) (succ y))) add | | | |
| | | | | | | | | |
| | | ↠β cond (iszero | | ) | | (add (pred | | ) (succ | | )) |
| | | | | | | | | |
| | | ↠β cond true | | (add (pred | | ) (succ | | )) |
| | | | | | | | | |
| | | | | | | | | | | |
|
Jätkame induktsiooni sammu m=m′+1 tõestusega, kus kasutame add-i definitsiooni järel püsipunktikombinaatori võrdust Y f =β f (Y f), teadmist iszero m+1 ↠β false , teadmist pred m+1 ↠β m, teadmist succ n ↠β n+1, teadmist cond false e1 e2 ↠β e2 ning induktsiooni hüpoteesi ∀ k, add m k ↠β m+k.
|
| | | =
Y (λf x y. cond (iszero x) y (f (pred x)(succ y))) | | | |
| | | | | | | | | |
| | | =β λf x y. cond (iszero x) y (f (pred x) (succ y)) add | | | |
| | | | | | | | | |
| | | ↠β cond (iszero | | ) y (add (pred | | ) (succ | | )) |
| | | | | | | | | |
| | | | | | | | | | | |
| | | | | | | | | | | |
| | | | | | | | | | | |
|
Sarnaselt liitmisoperatsioonile add saame kõik rekursiivsed definitsioonid kirjutada mitterekursiivselt, kasutades mõnda püsipunktioperaatorit. Üldine muster on, et funktsioonile tuleb lisada esimene parameeter ja sellega asendada kõik rekursiivsed väljakutsed. Nii saame funktsiooni, mis töötab soovitud viisil kuni rekursiivse väljakutseni. Kuidas aga anda funktsioonile see esimene argument? Seda teeb püsipunktioperaator.
Ehk kui soovime defineerida funktsiooni, mis käitub nagu võrdus f = λx y z. … (f a b c) … siis piisab meil see defineerida mitterekursiivse makrona f := Y (λf’ x y z. … (f’ a b c) …).