【问题标题】:Calling Haskell functions from Python从 Python 调用 Haskell 函数
【发布时间】:2011-06-28 06:39:48
【问题描述】:

我想使用 Python 中的一些 Haskell 库(例如 Darcs、Pandoc),但 Python 中似乎没有直接的外部函数接口到 Haskell。有什么办法吗?

【问题讨论】:

标签: python haskell binding ffi


【解决方案1】:

如果您可以让 Python 代码调用 C,则可以调用已通过 FFI 导出的 Haskell 函数

另一种方法是编写标准 IPC 接口,在 darcs 和 pandoc 的情况下,只是将它们称为普通可执行文件并解析它们的输出可能是可行的方法。

关于在 Haskell 端自动生成无聊、重复、FFI 和编组代码,我推荐c2hs,它允许您基于现有的 C 接口自动生成很多。 python可能也有类似的东西。

唉,据我所知,SWIG 从来没有为 Haskell 实现过,大概是因为它迎合了不太严格类型的语言。

【讨论】:

【解决方案2】:

另一个想法:比直接 C 绑定效率低,但比向 Haskell 发送更有效的是 rpc 系统,例如 Apache Thrift:http://incubator.apache.org/thrift/

我发现 Thrift 易于使用、支持良好且性能合理。一旦你的 Haskell 服务器运行起来,本地通信的成本就相当便宜了,尽管你在编组/解编组方面比直接使用 c 类型要付出更多的代价。

还有至少两个用于从 Haskell 调用 Python 的包,missingpy (http://hackage.haskell.org/package/MissingPy) 和 cpython (http://hackage.haskell.org/package/cpython)。后者声称已计划向另一个方向提供支持——尽管您必须询问作者是否仍然如此,如果是这样,何时出现。

【讨论】:

  • @sciv 你有没有在 Apache Thrift 中找到任何外部函数调用的例子?我在这里遇到了同样的问题。
  • 你是什么意思 ffi? thrift 是一个序列化和客户端/服务器库。
【解决方案3】:

对于 pandoc,至少,您可以使用这些 C 绑定: https://github.com/toyvo/libpandoc

【讨论】:

  • 谢谢!你的回答对我很有帮助。
【解决方案4】:

这里是菜鸟。

但我确实设法使用 Haskell 的 FFI 从 python 调用用户定义的 Haskell 函数。 基本上,我将 Haskell 函数编译为 dll,并在 python 中使用 ctypes 导入了 dll。 因此该函数在 python 中可用。

我在这里写了程序:https://justa0xc0de.wordpress.com/2015/01/08/using_haskell_function_in_python/

希望这会有所帮助。

【讨论】:

  • 这看起来很有用,但您应该提取一些关键思想并将它们复制到您的答案中。否则,它有被“仅链接”删除的风险。
【解决方案5】:

这里有一个包装器,允许人们从 Python 调用 Haskell 函数:

https://github.com/sakana/HaPy

粗略检查,似乎要求 Haskell 函数具有相对简单的类型签名(基本上,所有涉及的类型最好是 c 知道的 Int 和 Float 之类的东西,或者这种形式的东西的列表,或者列表列表等)。

提供了一个具有此 Haskell 代码的示例:

module ExampleModule where

import Data.Char

foo :: Double -> Double -> Double
foo = (*)

bar :: Int -> Int
bar i = sum [1..i]

baz :: Int -> Bool
baz = (> 5)

arr_arg :: [Int] -> Int
arr_arg = sum

arr_ret :: Int -> [Int]
arr_ret i = [1..i]

arr_complex :: [[Int]] -> [[Int]]
arr_complex = map (map (* 2))

string_fun :: String -> String
string_fun str = str ++ reverse str

char_test :: Char -> Int
char_test = ord

然后像这样访问它:

from HaPy import ExampleModule

print "3 * 7 is", ExampleModule.foo(3,7)
print "sum from 1 to 10 is", ExampleModule.bar(10)
print "3 > 5 is", ExampleModule.baz(3)

print "sum from 1 to 100 is", ExampleModule.arr_arg(range(101))
print "numbers from 1 to 10 are", ExampleModule.arr_ret(10)

print "complex array passing:", ExampleModule.arr_complex([range(3), [], range(100)])
print "string fun:", ExampleModule.string_fun("This isn't really a palindrome.")

s = ExampleModule.string_fun("abc\000def")
print "string fun with nulls:", s,
for c in s:
    print ord(c),
print

print "char test:", ExampleModule.char_test("t")

不幸的是,您确实需要在 Haskell 端做一些导出管道。

【讨论】:

    【解决方案6】:

    另一个选项是连字符,可以在here 找到。基本用法如下所示:

    >>> import hyphen, hs.Prelude
    >>> hs.Prelude.sum([1,2,3]) # list converted to Haskell list
    6
    >>> hs.Prelude.drop(5, "Hello, world")
    ", world"
    >>> hs.Prelude.drop(1, [1,2,3])
    <hs.GHC.Types.[] object of Haskell type [GHC.Integer.Integer], containing '[2,3]'>
    >>> list(hs.Prelude.drop(1, [1,2,3]))   # Convert back to Python list
    [2, 3]
    

    与其他答案中的其他选项相比,这似乎是一个轻量级的解决方案。

    作为额外重量的回报,您似乎获得了从 Haskell 到 Python 的完整桥梁。而HaPygithub.com/nh2/call-haskell-from-anything 仅允许您使用 Python 中的 Haskell 函数,前提是该 Haskell 函数的所有参数都来自相当基本的类型并返回相当基本的类型,hyphen 似乎允许您使用 arbitrary 函数。它可以做到这一点,因为它在 python 中引入了一种表示 Haskell 堆上的任意对象的类型。

    这些“从 python 中查看的 haskell 对象”表现得非常好,就像 python 对象一样。例如 Haskell Maps 的行为有点像字典:

    >>> import hs.Data.Map
    >>> my_map = hs.Data.Map.fromList([(1, 'Hello'), (2, 'World')])
    >>> my_map[1]
    'Hello'
    >>> print(sorted([key for key in my_map]))
    [1, 2]
    

    更多示例请参见自述文件!

    它似乎还可以处理各种奇特的事情,例如在 Haskell 和 Python 之间转换异常。

    【讨论】:

      猜你喜欢
      • 2017-03-12
      • 2017-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-30
      • 2013-08-30
      相关资源
      最近更新 更多