Created
May 9, 2012 17:06
-
-
Save bgnori/2646775 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
STDOUT = sys.stdout | |
"""http://en.wikipedia.org/wiki/Unlambda""" | |
class UnlambdaObject: | |
''' | |
wrong design.... just def was enough. | |
''' | |
def __call__(self, x): | |
pass | |
class Q(UnlambdaObject): | |
""" | |
It's not unlambda object. | |
""" | |
def __call__(self, x): | |
raise | |
class I(UnlambdaObject): | |
""" | |
i can be implemented as ``skk, since ```skkx yields x for all x. | |
""" | |
def __call__(self, x): | |
return x | |
class P(UnlambdaObject): | |
""" | |
The notation .x denotes a function which takes one argument and returns it unchanged, | |
printing the single character x as a side effect when it is invoked. | |
""" | |
def __init__(self, value): | |
self._value = value | |
def value(self): | |
return self._value | |
def __call__(self, x): | |
STDOUT.write(self.value()) | |
return x | |
class R(UnlambdaObject): | |
""" | |
The function r is syntactic sugar for the function that prints a newline character. | |
""" | |
def __call__(self, x): | |
STDOUT.write('\n') | |
return x | |
class K(UnlambdaObject): | |
""" | |
k manufactures constant functions: the result of `kx is a function which, | |
when invoked, returns x. Thus the value of ``kxy is x for any x and y. | |
""" | |
def __call__(self, x): | |
class K1(UnlambdaObject): | |
def __call__(self, y): | |
return x | |
return K1() | |
class S(UnlambdaObject): | |
""" | |
s is a generalized evaluation operator. ```sxyz evaluates to ``xz`yz for any x, y, and z. | |
""" | |
def __call__(self, x): | |
class S1(UnlambdaObject): | |
def __call__(self, y): | |
class S2(UnlambdaObject): | |
def __call__(self, z): | |
return x(z)(y(z)) | |
return S2() | |
return S1() | |
class C(UnlambdaObject): | |
""" | |
Unlambda's one flow control construction is call with current continuation, denoted c. | |
When an expression of the form `cx is evaluated, a special "continuation" object is | |
constructed, representing the state of the interpreter at that moment. Then x is | |
evaluated, and then the result is given the continuation object as an argument. | |
If the continuation is never applied to an argument, the value of the `cx expression is | |
the same as the value of x. But if the continuation object is applied to a value y, | |
execution of x is immediately aborted, and the value of the entire `cx expression is y. | |
""" | |
class D(UnlambdaObject): | |
""" | |
However, if x evaluates to the special value d, then y is not evaluated; instead, | |
the value of the expression `dy is a special "delayed computation" object, which, | |
when applied to an argument z, evaluates y, and then applies its value to z. | |
""" | |
class V(UnlambdaObject): | |
""" | |
Unlambda's next built-in operator is v, which ignores its argument and returns v. | |
This feature is not strictly necessary, since v could be implemented as | |
```s``k``sii``s``s`ksk`k``siik, | |
but it is supplied as a convenience. | |
(This expression above is simply `Yk, where Y denotes a fixed point combinator.) | |
""" | |
class UnlambdaEvaluator: | |
mapping = { | |
"`": Q, | |
".": P, | |
"r": R, | |
"k": K, | |
"i": I, | |
"s": S, | |
} | |
def __init__(self): | |
self.stack = [] | |
def push(self, x): | |
self.stack.append(x) | |
def pop(self): | |
return self.stack.pop() | |
def isQuote(self, nth): | |
return isinstance(self.stack[nth], Q) | |
def isOperator(self, nth): | |
return isinstance(self.stack[nth], UnlambdaObject) and not isinstance(self.stack[nth], Q) | |
def isOperand(self, nth): | |
return isinstance(self.stack[nth], UnlambdaObject) and not isinstance(self.stack[nth], Q) | |
def check_stack(self): | |
if len(self.stack) < 3: | |
return False | |
#print self.stack[-3:] | |
return self.isQuote(-3) and self.isOperator(-2) and self.isOperand(-1) | |
def evalone(self, obj): | |
self.push(obj) | |
if self.check_stack(): | |
operand = self.pop() | |
operator = self.pop() | |
assert isinstance(self.pop(), Q) | |
r = operator(operand) | |
assert isinstance(r, UnlambdaObject) | |
self.push(r) | |
def eval(self, xs): | |
while(xs): | |
x, xs = xs[0], xs[1:] | |
if x == ".": | |
x, xs = xs[0], xs[1:] | |
o = P(x) | |
else: | |
ctor = self.mapping.get(x) | |
o = ctor() | |
self.evalone(o) | |
ue = UnlambdaEvaluator() | |
hw = "`r```````````.H.e.l.l.o. .w.o.r.l.di" | |
ue.eval(hw) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment