我想使用 Python 中的一些 Haskell 库(例如 Darcs、Pandoc),但似乎在 Python 中没有与 Haskell 直接的外部函数接口。有没有办法做到这一点?
6 回答
如果您可以让 Python 代码调用 C,则可以调用已通过FFI导出的 Haskell 函数
另一种方法是编写一个标准的 IPC 接口,在 darcs 和 pandoc 的情况下,只是将它们称为 vanilla 可执行文件并解析它们的输出可能是可行的方法。
至于在 Haskell 端自动生成无聊的、重复的、FFI 和编组代码,我推荐c2hs,它允许您基于现有的 C 接口自动生成很多。python可能有类似的东西。
唉,据我所知,SWIG 从来没有为 Haskell 实现过,大概是因为它迎合了不太严格类型的语言。
另一种选择是连字符,可以在这里找到。基本用法如下所示:
>>> 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 的完整桥梁。而仅当 Haskell 函数的所有参数都来自相当基本的类型并返回相当基本的类型时,才允许您使用 Python 中的 Haskell 函数,这HaPy
似乎允许您使用任意函数。它可以做到这一点,因为它在 python 中引入了一种表示 Haskell 堆上的任意对象的类型。github.com/nh2/call-haskell-from-anything
hyphen
这些“从 python 中查看的 haskell 对象”的行为与 python 对象一样好。例如 HaskellMap
的行为有点像字典:
>>> 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]
有关更多示例,请参阅自述文件!
It also seems to handle various fancy things like converting exceptions between Haskell and Python.
另一个想法:比直接 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 )。后者声称计划在另一个方向上提供支持 - 尽管您必须询问作者是否仍然如此,如果是这样,何时。
菜鸟在这里。
但我确实设法使用 Haskell 的 FFI 从 python 调用用户定义的 Haskell 函数。基本上,我将 Haskell 函数编译为 dll,并在 python 中使用 ctypes 导入了 dll。因此该函数在 python 中可用。
我在这里写了程序:https ://justa0xc0de.wordpress.com/2015/01/08/using_haskell_function_in_python/
希望这可以帮助。
有一个包装器允许从 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 端做一些导出管道。
对于 pandoc,至少,您可以使用这些 C 绑定: https ://github.com/toyvo/libpandoc