Calling Haskell functions from Python

后端 未结 6 1987
醉话见心
醉话见心 2020-12-04 18:22

I want to use some Haskell libraries (e.g. Darcs, Pandoc) from Python, but it seems there’s no direct foreign function interface to Haskell in Python. Is there any way to do

相关标签:
6条回答
  • 2020-12-04 18:40

    Noob here.

    But I did manage to call user defined Haskell functions from python using Haskell's FFI. Basically I compiled the Haskell function to a dll and imported the dll using ctypes in python. So the function became available in python.

    I wrote the procedure here: https://justa0xc0de.wordpress.com/2015/01/08/using_haskell_function_in_python/

    Hope this helps.

    0 讨论(0)
  • 2020-12-04 18:42

    Another option is hyphen, which can be found here. Basic usage looks something like:

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

    This seems to be a less lightweight solution than some of the other options in other answers.

    In return for the extra weight, you seem to get a full bridge from Haskell to Python. Whereas HaPy and github.com/nh2/call-haskell-from-anything only allow you to use a Haskell function from Python if that Haskell function has all its arguments from fairly basic types and returns a fairly basic type, hyphen seems to let you use arbitrary functions. It can do this because it introduces into python a type representing an arbitrary object on the Haskell heap.

    These 'haskell objects viewed from python' behave fairly nicely as python objects. For example Haskell Maps behave a bit like dictionaries:

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

    See the readme for many more examples!

    It also seems to handle various fancy things like converting exceptions between Haskell and Python.

    0 讨论(0)
  • 2020-12-04 18:45

    One additional idea: Something less efficient than a direct C binding, but more efficient than shelling out to Haskell is an rpc system such as Apache Thrift: http://incubator.apache.org/thrift/

    I've found thrift easy to use, well supported, and reasonably performant. Once you have your Haskell server running, the cost of local communication is fairly cheap, although you pay a bit more in marshalling/unmarshalling than using c types directly.

    There are also at least two packages for calling Python from Haskell, missingpy (http://hackage.haskell.org/package/MissingPy) and cpython (http://hackage.haskell.org/package/cpython). The latter claims that support in the other direction is planned -- although you'd have to ask the author if this is still the case, and if so when.

    0 讨论(0)
  • 2020-12-04 18:51

    There is a wrapper that allows one to call Haskell functions from Python here:

    https://github.com/sakana/HaPy

    From a cursory inspection, it seems to require that the Haskell functions have relatively simple type signatures (basically, all the types involved had better be things like Int and Float which c knows about, or lists of things of this form, or lists of lists, or so on).

    An example is provided where one has this Haskell code:

    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
    

    and one accesses it like this:

    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")
    

    Unfortunately, you do need to do some export plumbing on the Haskell side.

    0 讨论(0)
  • 2020-12-04 18:55

    Provided you can get your Python code to call C, you can call Haskell functions that have been exported via the FFI

    Another approach would be to write a standard IPC interface, in the case of darcs and pandoc just calling them as vanilla executables and parsing their output might be the way to go.

    As to automating the generation of boring, repetitive, FFI and marshalling code on the Haskell side, I'd recommend c2hs, which allows you to auto-generate a lot based on an existing C interface. There's probably similar things for python.

    SWIG, alas, has, to the best of my knowledge, never been implemented for Haskell, presumably because it caters to less strictly-typed languages.

    0 讨论(0)
  • 2020-12-04 18:57

    For pandoc, at least, you can use these C bindings: https://github.com/toyvo/libpandoc

    0 讨论(0)
提交回复
热议问题