Вызов функций Haskell из Python

Я хочу использовать некоторые библиотеки Haskell (например, Darcs, Pandoc) из Python, но, похоже, нет прямого внешнего интерфейса функции для Haskell в Python. Есть ли способ сделать это?

6 ответов


при условии, что вы можете получить код Python для вызова C, вы можете вызвать функции Haskell, которые были экспортированы через FFI

другим подходом было бы написать стандартный интерфейс IPC, в случае darcs и pandoc, просто вызывая их как исполняемые файлы vanilla и анализируя их вывод, может быть путь.

Что касается автоматизации генерации скучного, повторяющегося, FFI и маршалинга кода на стороне Haskell, я бы рекомендовал c2hs, что позволяет автоматически генерировать много на основе существующего интерфейса C. Вероятно, для python есть похожие вещи.

SWIG, увы, насколько мне известно, никогда не был реализован для Haskell, предположительно потому, что он обслуживает менее строго типизированные языки.


одна дополнительная идея: что-то менее эффективное, чем прямая привязка C, но более эффективное, чем обстрел Haskell, - это система rpc, такая как Apache Thrift:http://incubator.apache.org/thrift/

Я нашел бережливость простой в использовании, хорошо поддерживается и разумно производительности. После запуска сервера Haskell стоимость локальной связи довольно дешевая, хотя вы платите немного больше в маршаллинге / немаршаллинге, чем при использовании типов c непосредственно.

есть также как минимум две упаковки для вызова Python из Хаскелл, missingpy (http://hackage.haskell.org/package/MissingPy) и с CPython (http://hackage.haskell.org/package/cpython). Последний утверждает, что поддержку в другом направлении планируется, хотя надо спросить у автора, если это все-таки дело, и если да, то когда.


другой вариант:тире, который можно найти здесь. Основное использование выглядит примерно так:

>>> 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. Тогда как HaPy и github.com/nh2/call-haskell-from-anything только позволяют использовать функцию Haskell из Python, если эта функция Haskell имеет все свои аргументы из справедливо основные типы и возвращает довольно базовый тип,hyphen кажется, позволяет использовать произвольные функции. Он может сделать это, потому что он вводит в python тип, представляющий произвольный объект в куче Haskell.

эти "объекты haskell, просматриваемые с python", ведут себя довольно хорошо как объекты 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]

см. readme для многих других примеров!

он также, кажется, обрабатывает различные причудливые вещи, такие как преобразование исключений между Haskell и Python.


существует оболочка, которая позволяет вызывать функции Haskell из Python здесь:

https://github.com/sakana/HaPy

из беглого осмотра, похоже, требуется, чтобы функции Haskell имели относительно простые сигнатуры типов (в основном, все вовлеченные типы должны быть такими вещами, как Int и Float, о которых знает c, или списки вещей этой формы, или списки списков, или так далее).

приведен пример, где есть этот код на 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("abc0def")
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


Нуб здесь.

но мне удалось вызвать пользовательские функции Haskell из python с помощью FFI Haskell. В основном я скомпилировал функцию Haskell в dll и импортировал dll с помощью ctypes в python. Таким образом, функция стала доступна в python.

Я написал процедуру здесь: https://justa0xc0de.wordpress.com/2015/01/08/using_haskell_function_in_python/

надеюсь, что это помогает.