Skip to content

Instantly share code, notes, and snippets.

@tjkendev
Last active February 28, 2017 08:49
Show Gist options
  • Save tjkendev/77b63547d5c56f98cb750e043ec52629 to your computer and use it in GitHub Desktop.
Save tjkendev/77b63547d5c56f98cb750e043ec52629 to your computer and use it in GitHub Desktop.
pythonでラムダ式使ってunlambdaを実行しようとして失敗したもの。関数cがcall/ccとして書けない。
# -*- 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,
# print
'.': 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