Я хочу использовать некоторые библиотеки Haskell (например, Darcs, Pandoc) из Python, но, похоже, в Python нет прямого интерфейса сторонних функций для Haskell. Есть ли способ сделать это?
Вызов функций 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 из Haskell, 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 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.
Нуб здесь.
Но мне удалось вызвать пользовательские функции Haskell из python, используя Haskell FFI. В основном я скомпилировал функцию Haskell в dll и импортировал dll, используя ctypes в python. Так функция стала доступна в питоне.
Я написал процедуру здесь: https://justa0xc0de.wordpress.com/2015/01/08/using_haskell_function_in_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("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