Я хочу использовать некоторые библиотеки Haskell (например, Darcs, Pandoc) из Python, но, похоже, для Haskell в Python нет прямого интерфейса с иностранными функциями. Есть ли способ сделать это?
Вызов функций Haskell из Python
Ответ 1
Если вы можете получить код Python для вызова C, вы можете вызвать функции Haskell, которые были экспортированы через FFI
Другим подходом было бы написать стандартный интерфейс IPC, в случае с darcs и pandoc, просто называя их исполняемыми файлами vanilla и анализируя их вывод, может быть, путь.
Что касается автоматизации генерации скучного, повторяющегося, FFI и кода маршаллинга на стороне Haskell, я бы рекомендовал c2hs, который позволяет автоматически генерировать множество на основе существующего интерфейса C. Вероятно, похожие вещи для python.
SWIG, увы, насколько мне известно, никогда не был реализован для Haskell, по-видимому, потому, что он обслуживает менее строго типизированные языки.
Ответ 2
Еще одна идея: что-то менее эффективное, чем прямое связывание C, но более эффективное, чем обход Haskell, представляет собой систему rpc, такую как Apache Thrift: http://incubator.apache.org/thrift/
Я нашел, что бережливость проста в использовании, хорошо поддерживается и достаточно эффективна. После того, как у вас запущен сервер Haskell, стоимость локального общения довольно дешевая, хотя вы платите немного больше за маршаллинг /unmarshalling, чем напрямую с использованием типов c.
Есть также как минимум два пакета для вызова Python из Haskell, missingpy (http://hackage.haskell.org/package/MissingPy) и cpython (http://hackage.haskell.org/package/cpython). Последний утверждает, что поддержка в другом направлении запланирована - хотя вы должны спросить автора, если это все еще так, и если да, то когда.
Ответ 3
Существует оболочка, которая позволяет называть функции Haskell из Python здесь:
https://github.com/sakana/HaPy
От беглого осмотра, кажется, требуется, чтобы функции Haskell имели относительно простые сигнатуры типа (в основном, все типы были лучше, например, такие, как 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.
Ответ 4
Другой вариант - дефис, который можно найти здесь. Основное использование выглядит примерно так:
>>> 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 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
Для pandoc, по крайней мере, вы можете использовать эти привязки C: https://github.com/toyvo/libpandoc
Ответ 6
Noob здесь.
Но мне удалось вызвать пользовательские функции Haskell из python с использованием Haskell FFI. В основном я скомпилировал функцию Haskell в dll и импортировал dll с помощью ctypes в python. Таким образом, функция стала доступна в python.
Я написал процедуру здесь: https://justa0xc0de.wordpress.com/2015/01/08/using_haskell_function_in_python/
Надеюсь, что это поможет.