Haskell In Python ver. 0.01
Haskellのコードを呼び出すための
Pythonモジュールを作ってみました。
= 既知の問題点。
=
使い方。
>>> from Haskell import Haskell
>>> h = Haskell("""
func = reverse
func' x = map (+ x)
value = 42
""")
>>> h.func
<Haskell.HaskellFunc object at 0x0153AC90>
>>> range(5)
[0, 1, 2, 3, 4]
>>> h.func(range(5))
[4, 3, 2, 1, 0]
>>> type(_)
<type 'list'>
>>> func2 = h.get("func'")
>>> func2(1, range(5))
[1, 2, 3, 4, 5]
>>> h.value
<Haskell.HaskellFunc object at 0x0153AD90>
>>> h.value()
42
>>> type(_)
<type 'int'>
仕組み。
PythonからHaskellを呼ぶためには、
- 1:PythonのオブジェクトをなんらかのHaskellが扱える形に変換
- 2:変換したモノを何らかの方法でHaskellに渡す
- 3:Haskellが渡されたモノをHaskellのオブジェクトに変換
- 4:Haskellが処理
- 5:処理の結果のHaskellオブジェクトをPythonが扱える形に変換
- 6:変換したモノを何らかの方法でPythonに渡す
- 7:Pythonが渡されたモノをPythonのオブジェクトに変換
このバージョン0.01では
- 1:Pythonのオブジェクトをstrを使って文字列に変換
- 2:変換した文字列をソースコードに埋め込んでHaskellを実行
- 3:Haskellパーサが文字列をパースしてHaskellのオブジェクトを作る
- 4:Haskellが処理
- 5:処理の結果のHaskellオブジェクトをshowで文字列に変換する
- 6:文字列を標準出標準出力に力に吐いて、Pythonがそれを拾う
- 7:Pythonが文字列をevalしてPythonのオブジェクトに変換
= 既知の問題点。
- 5番の変換にshowを使っているのでShowのインスタンスでないとPython側に渡せない。
また、Showのインスタンスであって、Python側に渡せたとしても7番の変換でこけるケースがある。
- 例えば関数はShowのインスタンスでないので渡せない
- 例えば「Just 1」はShowのインスタンスなので渡せるけどevalできない
- 解決法:
- たとえばPythonizableというクラスを作って、Intなどをそのインスタンスにする。
- toPython :: (Pythonizable a) => a -> String を作る
- HaskellでPythonの関数をpureな関数として扱えない
- Pythonと通信するためにIOモナドになってしまうから
- Haskellのコードで記述するのではなく、なにか拡張を作ってHaskell処理系をだましてやる必要がある
=
'''
Haskell In Python
USAGE:
code = """
func = reverse
func' x = map (+ x)
value = 42
"""
h = Haskell(code)
print h.func(range(5))
print h.get("func'")(1, range(5))
print h.value()
'''
__all__ = ["Haskell"]
class Haskell(object):
def __init__(self, code):
self.code = code
def __getattr__(self, name):
return HaskellFunc(self.code, name)
def get(self, name):
return HaskellFunc(self.code, name)
class HaskellFunc(object):
def __init__(self, code, name):
self.code = code
self.name = name
def __call__(self, *args):
argsStr = " ".join(str(arg) for arg in args)
f = file("tmp.hs", "w")
print >>f, self.code
print >>f, "main = print $ %s %s" % (self.name, argsStr)
f.close()
from popen2 import popen3
(o, i, e) = popen3("runghc tmp.hs")
err = e.read()
if err:
raise RuntimeError(err)
return haskellStr2pythonObj(o.read())
def haskellStr2pythonObj(s):
return eval(s)
フィードバック
> Haskellのコードを呼び出すための Pythonモジュールを作ってみました。
お!
でも最近はこういう方法での貼り合わせより、Pythonがプリプロセッサとして走るののほうが便利かも知れないなぁと思ったり。