In der FH ist das Lambda-Kalkül gerade Thema. Um nicht die Übungsaufgaben per Hand auf Papier zu rechnen,
habe ich in BMax die Abstrakte-Syntax, die Relationen und einen Interpreter geschrieben. Das ganze ist inspiriert von http://www.youtube.com/watch?v=brmpy3TnYJk.
Funktionsumfang:
- Lambda-Terme können als abstrakte Syntax erstellt werden, z. B. Code: [AUSKLAPPEN] [EINKLAPPEN] \x -> xy wird zu BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Ab("x", App(Vr("x"), Vr("y")))
- Alpha-Äquivalenz BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] AlphaEq(t1, t2) testest auf Gleichheit beider Terme t1, t2. Beispiel: Code: [AUSKLAPPEN] [EINKLAPPEN] \x.x =alpha \y.y und in BMax:BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Local t1 : Term = Ab("x", Vr("x")) Local t2 : Term = Ab("y", Vr("y")) AlphaEq(t1, t2)
- Beta-Relation: Testest auf Gleichheit beider Terme t1, t2, wobei t1 ein Redex ist und nach Auswerten Alpha-Äquivalent mit t2 sein muss. Vergleichbar mit Code: [AUSKLAPPEN] [EINKLAPPEN] (5 + 3) ->beta 8 Beispiel: Code: [AUSKLAPPEN] [EINKLAPPEN] (\x.x)y -> beta y und in BMax: BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Local t1 : Term = App(Ab("x", Vr("x")), Vr("y")) Local t2 : Term = Vr("y") Beta1(t1, t2)
- Auswertung des i-ten Redex: BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Eval : Term(t : Term, i : Int)
Hier noch ein paar Hilfsfunktionen, um im Lambda-Kalkül auch zu Programmieren:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Function LambdaPairSelector : Term(i : Int) Return Ab("t", App(Vr("t"), Ab("d1", Ab("d2", Vr("d" + i))))) End Function
Function LambdaPair : Term(d1 : Term, d2 : Term) Return Ab("s", App(App(Vr("s"), d1), d2)) End Function
Global LambdaTrue : Term = Ab("x", Ab("y", Vr("x")))
Global LambdaFalse : Term = Ab("x", Ab("y", Vr("y")))
Local LambdaZero : Term = Ab("x", Vr("x"))
Function LambdaSucc : Term(n : Term) Return LambdaPair(LambdaFalse, n) End Function
Function LambdaPred : Term(n : Term) Return App(LambdaPairSelector(2), n) End Function
Global LambdaIsZero : Term = LambdaPairSelector(1)
Function LambdaIf : Term(c : Term, t : Term, e : Term) Return App(App(c, t), e) End Function
Function LambdaLet : Term(x : String, e1 : Term, e2 : Term) Return App(Ab(x, e2), e1) End Function
Local LambdaThetaHalf : Term = Ab("x", Ab("y", App(Vr("y"), App(App(Vr("x"), Vr("x")), Vr("y"))))) Global LambdaTheta : Term = App(LambdaThetaHalf, LambdaThetaHalf)
Function LambdaRec : Term(f : String, b : Term) Return App(LambdaTheta, Ab("t", Subst(b, f, Vr("t")))) End Function
Function LambdaNot : Term(n : Term) Return LambdaIf(n, LambdaFalse, LambdaTrue) End Function
Function LambdaAnd : Term(a : Term, b : Term) Return LambdaIf(a, b, LambdaFalse) End Function
Function LambdaOr : Term(a : Term, b : Term) Return LambdaIf(a, LambdaTrue, b) End Function
Global LambdaAdd : Term = LambdaRec("add",.. Ab("a", Ab("b", LambdaIf(App(LambdaIsZero, Vr("b")), .. Vr("a"), .. LambdaSucc(App(App(Vr("add"), Vr("a")), LambdaPred(Vr("b"))))))))
Global LambdaMult : Term = LambdaRec("mult",.. Ab("a", Ab("b", LambdaIf(App(LambdaIsZero, Vr("b")), .. LambdaZero, .. App(App(LambdaAdd, Vr("a")), App(App(Vr("mult"), Vr("a")), LambdaPred(Vr("b")))) ))))
Function EvalLeftOutermost : Term (t : Term) Print t.toString() Local t2 : Term Repeat t2 = t t = Eval(t2, 0) Print t.toString() Until AlphaEq(t, t2)
Return t2 End Function
Folgendes Programm sei im Lambda-Kalkül umzusetzen:
Code: [AUSKLAPPEN] [EINKLAPPEN] t = (if true then 0 else 0 + 1)
In BMax ist das:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] Local t : Term = LambdaIf(LambdaTrue, LambdaZero, LambdaSucc(LambdaZero)) Print "t: " + t.toString()
Local t2 : Term = Eval(t, 0) Print "t2: " + t2.toString()
Local t3 : Term = Eval(t2, 0) Print "t3: " + t3.toString()
Herauskommt "(\#1.#1)", was Alpha-Äquivalent zu "\x.x" ist, also LambdaZero. Wenn man statt LambdaTrue LambdaFalse in die Condition einsetzt, kommt auch LambdaSucc(LambdaZero) heraus.
Hier die Bibliothek:
BlitzMax: [AUSKLAPPEN] [EINKLAPPEN] SuperStrict
Framework BRL.Blitz Import BRL.StandardIO Import BRL.LinkedList
Global counter : Int = 0
Type Term Abstract Method toString : String() Abstract End Type
Type Variable Extends Term Field name : String Method toString : String() Return name End Method End Type
Type Application Extends Term Field operator : Term Field operand : Term Method toString : String() Return "(" + operator.toString() + operand.toString() + ")" End Method End Type
Type Abstraction Extends Term Field parameter : String Field body : Term Method toString : String() Return "(\" + parameter + "." + body.toString() + ")" End Method End Type
Function Vr : Variable(name : String) Local v : Variable = New Variable v.name = name Return v End Function
Function App : Application(operator : Term, operand : Term) Local app : Application = New Application app.operator = operator app.operand = operand Return app End Function
Function Ab : Abstraction(parameter : String, body : Term) Local abst : Abstraction = New Abstraction abst.parameter = parameter abst.body = body Return abst End Function
Function AddSingleton(element : Object, set : TList) Local exist : Int = False For Local e : Object = EachIn set If e = element Then exist = True Exit EndIf Next If Not exist Then set.addLast(element) End Function
Function Union(s1 : TList, s2 : TList) For Local e : Object = EachIn s1 AddSingleton(e, s2) Next End Function
Function SetToString : String(s : TList) Local str : String = "{" For Local e : String = EachIn s str = str + (e + ", ") Next If s.count() > 0 Then str = str[..(str.length - ", ".length)] str :+ "}" Return str End Function
Function FV : TList (t : Term) If Variable(t) Then Local v : Variable = Variable(t) Local s : TList = New TList AddSingleton(v.name, s) Return s ElseIf Application(t) Then Local app : Application = Application(t) Local s1 : TList = FV(app.operator) Local s2 : TList = FV(app.operand) Union(s2, s1) Return s1 ElseIf Abstraction(t) Then Local abst : Abstraction = Abstraction(t) Local s : TList = FV(abst.body) s.remove(abst.parameter) Return s EndIf End Function
Function BV : TList (t : Term) If Variable(t) Then Local s : TList = New TList Return s ElseIf Application(t) Then Local app : Application = Application(t) Local s1 : TList = BV(app.operator) Local s2 : TList = BV(app.operand) Union(s2, s1) Return s1 ElseIf Abstraction(t) Then Local abst : Abstraction = Abstraction(t) Local s : TList = BV(abst.body) AddSingleton(abst.parameter, s) Return s EndIf End Function
Function SwapString : String(x : String, y : String, v : String) If v = x Then Return y ElseIf v = y Then Return x Else Return v EndIf End Function
Function Swap : Term(x : String, y : String, t : Term) If Variable(t) Then Local v : Variable = Variable(t) Return Vr(SwapString(x, y, v.name)) ElseIf Application(t) Then Local a : Application = Application(t) Return App(Swap(x, y, a.operator), Swap(x, y, a.operand)) ElseIf Abstraction(t) Then Local a : Abstraction = Abstraction(t) Return Ab(SwapString(x, y, a.parameter), Swap(x, y, a.body)) EndIf End Function
Function AlphaEq : Int (t1 : Term, t2 : Term) If Variable(t1) And Variable(t2) Then Local var1 : Variable = Variable(t1) Local var2 : Variable = Variable(t2) Return var1.name = var2.name ElseIf Application(t1) And Application(t2) Then Local app1 : Application = Application(t1) Local app2 : Application = Application(t2) Return AlphaEq(app1.operator, app2.operator) And AlphaEq(app1.operand, app2.operand) ElseIf Abstraction(t1) And Abstraction(t2) Then Local abs1 : Abstraction = Abstraction(t1) Local abs2 : Abstraction = Abstraction(t2) If abs1.parameter = abs2.parameter Then Return AlphaEq(abs1.body, abs2.body) ElseIf Not FV(abs1.body).contains(abs2.parameter) Then Return AlphaEq(Swap(abs1.parameter, abs2.parameter, abs1.body), abs2.body) Else Return False EndIf Else Return False EndIf End Function
Function FreshName : String() counter :+ 1 Return "#" + counter End Function
Function Subst : Term (a : Term, x : String, n : Term) If Variable(a) Then Local vr : Variable = Variable(a) If vr.name = x Then Return n Else Return vr EndIf ElseIf Application(a) Then Local ap : Application = Application(a) Return App(Subst(ap.operator, x, n), Subst(ap.operand, x, n)) ElseIf Abstraction(a) Local abst : Abstraction = Abstraction(a) If abst.parameter = x Then Return abst Else If FV(n).contains(abst.parameter) Then Local z : String = FreshName() Return Ab(z, Subst(Swap(abst.parameter, z, abst.body), x, n)) Else Return Ab(abst.parameter, Subst(abst.body, x, n)) EndIf EndIf EndIf End Function
Function Beta1 : Int (t1 : Term, t2 : Term) If Application(t1) Then Local ap : Application = Application(t1) If Abstraction(ap.operator) Then Local ab : Abstraction = Abstraction(ap.operator) Return AlphaEq(Subst(ab.body, ab.parameter, ap.operand), t2) Else Return False EndIf Else Return False EndIf End Function
Function IsRedex : Int (t : Term) If Application(t) Then Local ap : Application = Application(t) If Abstraction(ap.operator) Then Return True Else Return False EndIf Else Return False EndIf End Function
Function Eval1 : Term (t : Term) If Application(t) Then Local ap : Application = Application(t) If Abstraction(ap.operator) Then Local ab : Abstraction = Abstraction(ap.operator) Return Subst(ab.body, ab.parameter, ap.operand) Else Throw "in t = FA is F not an abstraction" EndIf Else Throw "t is not an application" EndIf End Function
Function Eval : Term (t : Term, pos : Int = 0) If pos = 0 And IsRedex(t) Then Return Eval1(t) Else Local t2 : Term = CopyTerm(t) InnerEval(t2, 0, pos) Return t2 EndIf End Function
Function CopyTerm : Term (t : Term) If Variable(t) Then Local v : Variable = Variable(t) Return Vr(v.name) ElseIf Application(t) Then Local a : Application = Application (t) Return App(CopyTerm(a.operator), CopyTerm(a.operand)) ElseIf Abstraction(t) Then Local a : Abstraction = Abstraction(t) Return Ab(a.parameter, CopyTerm(a.body)) EndIf End Function
Function InnerEval : Int (t : Term, accu : Int, pos : Int) If Variable(t) Then Return accu ElseIf Application(t) Then Local ap : Application = Application(t) Local f : Term = ap.operator If IsRedex(f) Then If accu = pos Then ap.operator = Eval1(f) accu :+ 1 Else accu = InnerEval(f, accu + 1, pos) EndIf Else accu = InnerEval(f, accu, pos) EndIf Local a : Term = ap.operand If IsRedex(a) Then If accu = pos Then ap.operand = Eval1(a) accu :+ 1 Else accu = InnerEval(a, accu + 1, pos) EndIf Else accu = InnerEval(a, accu, pos) EndIf Return accu ElseIf Abstraction(t) Then Local abst : Abstraction = Abstraction(t) Local x : String = abst.parameter Local b : Term = abst.body If IsRedex(b) Then If accu = pos Then abst.body = Eval1(b) accu :+ 1 Else accu = InnerEval(b, accu + 1, pos) EndIf Else accu = InnerEval(b, accu, pos) EndIf Return accu EndIf End Function
Function PrintTree(t : Term, d : String = "") If Variable(t) Then Print d + "Var " + t.toString() + " | 0" ElseIf Application(t) Then Local ap : Application = Application(t) Print d + "App " + ap.toString() + " | " + IsRedex(t) PrintTree(ap.operator, d + " ") PrintTree(ap.operand, d + " ") ElseIf Abstraction(t) Then Local abstr : Abstraction = Abstraction(t) Print d + "Abs " + t.toString() + " | 0" PrintTree(abstr.body, d + " ") EndIf End Function
Ciao Olli
|