Skip to content

Instantly share code, notes, and snippets.

@bgnori
Created May 9, 2012 16:24
Show Gist options
  • Save bgnori/2646200 to your computer and use it in GitHub Desktop.
Save bgnori/2646200 to your computer and use it in GitHub Desktop.
import sys
STDOUT = sys.stdout
"""http://en.wikipedia.org/wiki/Unlambda"""
class UnlambdaObject:
def __call__(self, x):
pass
class Q(UnlambdaObject):
"""
It's not unlambda object.
"""
def __call__(self, x):
raise
class Data(UnlambdaObject):
"""
"""
def __init__(self, value):
self._value = value
def value(self):
return self._value
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 __call__(self, x):
print x
STDOUT.write(x.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.
"""
class S(UnlambdaObject):
"""
s is a generalized evaluation operator. ```sxyz evaluates to ``xz`yz for any x, y, and z.
"""
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,
}
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 make(self, x):
ctor = self.mapping.get(x, None)
if ctor:
return ctor()
else:
return Data(x)
def readone(self, x):
obj = self.make(x)
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):
for x in xs:
#print x
#print self.stack
self.readone(x)
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