Вызов функций из Haskell из Python - PullRequest
28 голосов
/ 16 февраля 2011

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

Ответы [ 6 ]

18 голосов
/ 16 февраля 2011

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

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

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

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

9 голосов
/ 16 февраля 2011

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

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

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

7 голосов
/ 07 ноября 2015

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

>>> 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]

Это кажется менее легким решением, чем некоторые другие варианты в других ответах.

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

Эти 'объекты haskell, рассматриваемые из python', ведут себя довольно хорошо как объекты python.Например, Haskell Map ведут себя немного как словари:

>>> 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.

5 голосов
/ 13 октября 2015

Здесь есть обертка, которая позволяет вызывать функции 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("abc\000def")
print "string fun with nulls:", s,
for c in s:
    print ord(c),
print

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

К сожалению, вам необходимо выполнить некоторые экспортные операции на стороне Haskell.

5 голосов
/ 11 января 2015

Нуб здесь.

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

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

Надеюсь, это поможет.

4 голосов
/ 17 февраля 2011

Для pandoc, по крайней мере, вы можете использовать эти привязки C: https://github.com/toyvo/libpandoc

...