« Befunge日記 |Main| IKEA日記 »

« Jythonでハノイの塔の可聴化 | Python | immutableクイズ »

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のオブジェクトに変換
という感じになっています。 変換処理をそれぞれの言語の処理系に丸投げしたので40行程度でかけました。
= 既知の問題点。

  • 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)

トラックバック(Trackback)

Trackback URL: http://www.nishiohirokazu.org/mt/mt-tb.cgi/542

フィードバック

by yu | 2007年03月28日 01:08

> Haskellのコードを呼び出すための Pythonモジュールを作ってみました。

お!

お! 大したものじゃないですが。

でも最近はこういう方法での貼り合わせより、Pythonがプリプロセッサとして走るののほうが便利かも知れないなぁと思ったり。

ご意見・ご感想をお送りください(フィードバック)

(フィードバックはメールで送信され、基本的に表示されませんが、内容によっては公開させていただくこともございます。ご了承ください。Your comment doesn't appear the page immediately. If the comment has value to other people, it will be put on the page or subsequent entries. Thank you.)

上の情報は、いずれも未記入でかまいません。 All of above questions are optional.