Last active
February 28, 2017 08:49
-
-
Save tjkendev/77b63547d5c56f98cb750e043ec52629 to your computer and use it in GitHub Desktop.
pythonでラムダ式使ってunlambdaを実行しようとして失敗したもの。関数cがcall/ccとして書けない。
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
# -*- encoding: utf-8 -*- | |
u""" | |
Unlambdaをpython上で実行するプログラム | |
""" | |
import sys | |
import inspect | |
import greenlet | |
# User Exception | |
class UnlambdaSyntaxError(Exception): | |
pass | |
class UnlambdaExit(Exception): | |
status = None | |
def __init__(self, e, status): | |
Exception.__init__(self, e) | |
self.status = status | |
sys.setrecursionlimit(10**5) | |
def debug(name, obj): | |
print "===== %s ====" % name | |
print obj | |
if callable(obj): | |
print inspect.getargspec(obj) | |
code, line = inspect.getsourcelines(obj) | |
print "line", line | |
print "'''" | |
print "".join(code) | |
print "'''" | |
print "="*10 | |
return obj | |
def unlambda(code, stdin=""): | |
u""" | |
Unlambdaのプログラムを実行する | |
params: | |
code: Unlambdaプログラム | |
stdin: Unlambdaへの入力 | |
return: | |
result_func: 終了時に残った関数 | |
stdout: 実行出力結果 | |
""" | |
def scan(s): | |
for c in s: | |
yield c | |
sc0 = scan(code).next | |
def sc(): | |
try: | |
x = sc0() | |
except StopIteration: | |
raise UnlambdaSyntaxError( | |
"invalid syntax : reach the end of program without exit" | |
) | |
return x | |
# current character | |
c_chara = [None] | |
# standard input | |
si = scan(stdin).next | |
# read from stdin | |
def read(): | |
try: | |
c_chara[0] = si() | |
return True | |
except StopIteration: | |
c_chara[0] = None | |
return False | |
# stdout | |
stdout = [] | |
def put(s, t): | |
stdout.append(s) | |
return t | |
# 関数の適用 | |
# f, x: 未評価のf,x | |
def op_apply(f, x): | |
op = f() | |
if op == "delay": | |
# 遅延評価 | |
return lambda y: op_apply(x, lambda: y) | |
return op(x()) | |
# 評価済み関数の適用 | |
# f, x: 評価済みのf,x | |
def raw_apply(f, x): | |
return op_apply(lambda:f, lambda: x) | |
# call/cc | |
# `cX => `X<cont> | |
# `<cont X>Y => Y (`cXを評価した時点に戻って、`cXをYに置き換えた形で再開) | |
# e.g.) ``cir -> ``i<cont>r -> `<cont>r -(`ciをrに置き換えた形で再開[`(`ci => r)r])-> `rr -(改行出力)-> r | |
def call_cc(func): | |
self = greenlet.getcurrent() | |
def callback(x): | |
# <cont>部分 | |
self.switch(x) | |
def func_call(): | |
res = func(callback) | |
return res | |
gr = greenlet.greenlet(func_call) | |
# TODO: returnされてからのcallback呼び出しにも対応したい(call/ccがしたいんじゃ) | |
# returnをtry-catchで囲んで、callback内でExceptionを投げる方法も可能だけど、return後には対応できず | |
return gr.switch() | |
# send Exit Exception | |
def unlambda_exit(x): | |
raise UnlambdaExit("Unlambda exit", x) | |
def nxt(): | |
t = { | |
# function application | |
'`': lambda: (lambda f, x: lambda: op_apply(f, x))(nxt(), nxt()), | |
# substitution | |
's': lambda: lambda: lambda x: lambda y: lambda z: raw_apply(raw_apply(x, z), raw_apply(y, z)), | |
# constant generator | |
'k': lambda: lambda: lambda x: lambda y: x, | |
# identity | |
'i': lambda: lambda: lambda x: x, | |
'.': lambda: (lambda c: lambda: lambda a: put(c, a))(sc()), | |
# carriage return | |
'r': lambda: lambda: lambda a: put("\n", a), | |
# black hole | |
'v': lambda: lambda: lambda e: t['v']()(), | |
# delay | |
'd': lambda: lambda: "delay", | |
# call/cc | |
'c': lambda: lambda: lambda f: call_cc(lambda cc: raw_apply(f, cc)), | |
# only in Unlambda version 2 and greater | |
# exit: `eX -> exit with status X | |
'e': lambda: lambda: lambda x: unlambda_exit(x), | |
# read: `@X -> `Xi (if successfull) or `Xv (if not) | |
'@': lambda: lambda: lambda x: raw_apply(x, t['i' if read() else 'v']()()), | |
# compare character read: `?xX -> `Xi (if x == current character) or `Xv (if not) | |
'?': lambda: (lambda c: lambda: lambda x: raw_apply(x, t['i' if c_chara[0] == c else 'v']()()))(sc()), | |
# reprint character read: `|X -> `X.x (if current character exists and is x) or `Xv (if current character does not exist) | |
'|': lambda: lambda: lambda x: raw_apply(x, lambda a: put(c_chara[0], a) if c_chara[0] else t['v']()()), | |
} | |
x = sc() | |
if x not in t: | |
raise UnlambdaSyntaxError("%s is not Unlambda function" % x) | |
return t[x]() | |
try: | |
res = nxt()() | |
except UnlambdaExit, e: | |
res = e.status | |
return (res, "".join(stdout)) | |
if __name__ == '__main__': | |
res, stdout = unlambda(raw_input("code: "), raw_input("stdin: ")) | |
print debug("result", res) | |
print "===== output =====" | |
print stdout | |
print "=====" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment