Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Foreign Inline Code in Haskell (Haskell Symposium 2014)

Foreign Inline Code in Haskell (Haskell Symposium 2014)

This talk was presented at the Haskell Symposium 2014 (Gothenburg, Sweden). A video of the talk is available from http://www.youtube.com/watch?v=pm_WFnWqn20

I show that quasiquoting in Template Haskell enables a new form of language interoperability. Specifically, for C-like languages it presents a purely library-based system for inline C code in Haskell. This dramatically simplifies language interoperability, and especially, the use of frameworks and libraries written in C-like languages from Haskell. It is, for example, helpful in applications based on native GUI libraries and projects integrating code written in multiple languages.

In this talk, I outline the limitations of existing approaches to using foreign libraries from Haskell. I argue that we can improve the situation with foreign inline code and demonstrate the approach at a few examples that interoperate with Objective-C.

Manuel Chakravarty

September 05, 2014
Tweet

More Decks by Manuel Chakravarty

Other Decks in Programming

Transcript

  1. Manuel M T Chakravarty
    University of New South Wales
    Foreign Inline Code in Haskell
    mchakravarty
    TacticalGrace
    justtesting.org
    1
    Tuesday, 9 September 14
    25 minute time slot: 20min talking + 5min [10min The Problem; 10min Inline Objective-C by Example]
    » I like to show you a new way for Haskell to play nicely with other programming languages.
    » I will demonstrate this at the example of Objective-C, but the same idea works for other languages as well.

    View full-size slide

  2. 2
    Tuesday, 9 September 14
    » Imagine you want to write a great new app in Haskell!

    View full-size slide

  3. 2
    Tuesday, 9 September 14
    » Imagine you want to write a great new app in Haskell!

    View full-size slide

  4. λ
    3
    Tuesday, 9 September 14
    » ...then you will need to use many existing frameworks and libraries.
    » Luckily, Haskell has a versatile foreign function interface as well as supporting tools.

    View full-size slide

  5. “Problem solved?”
    4
    Tuesday, 9 September 14
    » Does that solve the problem of language interoperability?
    » Let me explain that at an example...

    View full-size slide

  6. “Problem solved?”
    No!
    4
    Tuesday, 9 September 14
    » Does that solve the problem of language interoperability?
    » Let me explain that at an example...

    View full-size slide

  7. dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <- stringWithContentsOfUrl urlString
    putStr urlData
    What we want to write
    5
    Tuesday, 9 September 14
    * Kind of fair enough, after all the API we want to call —here, Cocoa— presents this interface.

    View full-size slide

  8. dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <- stringWithContentsOfUrl urlString
    putStr urlData
    What we want to write
    char *stringWithContentsOfUrlCstub(char *urlString)
    {
    NSURL *url = [NSURL URLWithString:urlString];
    [NSString
    stringWithContentsOfURL:url
    encoding:NSUTF8StringEncoding
    error:NULL];
    }
    What we want to call (& need to put into an extra file)
    5
    Tuesday, 9 September 14
    * Kind of fair enough, after all the API we want to call —here, Cocoa— presents this interface.

    View full-size slide

  9. What we have to write as well…
    foreign import stringWithContentsOfURLCstub
    :: CString -> IO CString
    stringWithContentsOfURL :: String -> IO String
    stringWithContentsOfURL url =
    withCString url $ \urlC -> do
    resultC <-
    stringWithContentsOfURLCstub urlC
    result <- peek resultC
    free resultC
    return result
    6
    Tuesday, 9 September 14
    » FFI code: If you find it confusing, that’s fine, as I want to argue that you shouldn’t write it in
    the first place.
    * Anything extensively relying on foreign frameworks will be a pain
    [Hybrid languages (eg, F# & Scala) have a different set of trade offs and focus on one foreign
    language, but don’t necessarily solve this problem either.]

    View full-size slide

  10. Bridging Libraries 1-to-1 transliteration of types & functions
    7
    Tuesday, 9 September 14
    * Bridging or binding libraries transliterate types & functions
    * Need to be maintained and documented; track multiple versions of base library
    * Lack of type safety
    * Tools and dynamic transliteration (by reflection) help

    View full-size slide

  11. C➙Haskell
    c2hs
    A case study
    GTK+
    8
    Tuesday, 9 September 14
    * c2hs: automation for bridging C libraries to Haskell c2hs>
    * Implements large parts of a C compiler front-end
    * Bridge for the cross-platform Gnome GUI library GTK+ gtk2hs/>

    View full-size slide

  12. 9
    Tuesday, 9 September 14
    * AFAIK, currently the only fully featured and properly maintained Haskell GUI library
    * Haskell GTK+ library is used for realistic applications

    View full-size slide

  13. “Does this approach scale?”
    10
    Tuesday, 9 September 14
    » Read question
    * It requires significant resources & constant effort to track the original library
    * Application frameworks: enormous and growing footprint

    View full-size slide

  14. February 2011
    Introduction of GTK+ 3
    11
    Tuesday, 9 September 14
    * Base GTK+ development isn’t even particularly fast
    * Bridging libraries lag behind their base libraries
    * Another example: Haskell OpenGL library

    View full-size slide

  15. February 2011
    Introduction of GTK+ 3
    December 2013
    GTK+ 3 in Haskell Bridge
    11
    Tuesday, 9 September 14
    * Base GTK+ development isn’t even particularly fast
    * Bridging libraries lag behind their base libraries
    * Another example: Haskell OpenGL library

    View full-size slide

  16. 12
    Tuesday, 9 September 14
    * Compared to modern application frameworks, GTK+ is small!

    View full-size slide

  17. Bridging libraries
    don’t scale Too much weight!
    13
    Tuesday, 9 September 14

    View full-size slide

  18. “Interoperability is an old
    problem — maybe an old
    solution can help?”
    14
    Tuesday, 9 September 14

    View full-size slide

  19. 15
    Tuesday, 9 September 14
    * Modula-2 with inline 68000 assembly
    * Assembly code can symbolically refer to Modula-2 entities (e.g., variables)

    View full-size slide

  20. 15
    Tuesday, 9 September 14
    * Modula-2 with inline 68000 assembly
    * Assembly code can symbolically refer to Modula-2 entities (e.g., variables)

    View full-size slide

  21. 15
    Tuesday, 9 September 14
    * Modula-2 with inline 68000 assembly
    * Assembly code can symbolically refer to Modula-2 entities (e.g., variables)

    View full-size slide

  22. “Inline C, C++, Objective-C, …
    in Haskell?”
    16
    Tuesday, 9 September 14
    * We don’t want to build front ends for a few more languages into GHC
    * How do we share entities between the languages?

    View full-size slide

  23. HASKELL WORKSHOP 2002
    HASKELL WORKSHOP 2007
    17
    Tuesday, 9 September 14
    » We use Template Haskell's general quasi-quotation support…

    View full-size slide

  24. dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <- stringWithContentsOfUrl urlString
    putStr urlData
    What we want to write
    char *stringWithContentsOfUrlCstub(char *urlString)
    { return
    ;
    }
    What we want to call (& need to put into an extra file)
    [NSString
    stringWithContentsOfURL:
    [NSURL URLWithString:urlString]
    encoding:NSUTF8StringEncoding
    error:NULL]
    18
    Tuesday, 9 September 14
    » Let's go back to out initial example of reading from a URL…
    » …and inline the Objective-C code into Haskell.

    View full-size slide

  25. dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <- stringWithContentsOfUrl urlString
    putStr urlData
    char *stringWithContentsOfUrlCstub(char *urlString)
    { return
    ;
    }
    [NSString
    stringWithContentsOfURL:
    [NSURL URLWithString:urlString]
    encoding:NSUTF8StringEncoding
    error:NULL]
    stringWithContentsOfUrl
    stringWithContentsOfUrl
    18
    Tuesday, 9 September 14
    » Let's go back to out initial example of reading from a URL…
    » …and inline the Objective-C code into Haskell.

    View full-size slide

  26. [NSString
    stringWithContentsOfURL:
    [NSURL URLWithString:urlString]
    encoding:NSUTF8StringEncoding
    error:NULL]
    putStr urlData
    dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <-
    19
    Tuesday, 9 September 14

    View full-size slide

  27. [NSString
    stringWithContentsOfURL:
    [NSURL URLWithString:urlString]
    encoding:NSUTF8StringEncoding
    error:NULL]
    putStr urlData
    dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <-
    20
    Tuesday, 9 September 14

    View full-size slide

  28. Language.C.Inline
    dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <-
    putStr urlData
    [NSString
    stringWithContentsOfURL:
    [NSURL URLWithString:urlString]
    encoding:NSUTF8StringEncoding
    error:NULL]
    21
    Tuesday, 9 September 14
    * Inline Objective-C
    * To have Objective-C in the middle of a Haskell function definition, we use a quasiquoter for
    C & Objective-C

    View full-size slide

  29. Language.C.Inline
    dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <-
    putStr urlData
    [NSString
    stringWithContentsOfURL:
    [NSURL URLWithString:urlString]
    encoding:NSUTF8StringEncoding
    error:NULL]
    [cexp|
    |]
    quasiquoted Objective-C
    21
    Tuesday, 9 September 14
    * Inline Objective-C
    * To have Objective-C in the middle of a Haskell function definition, we use a quasiquoter for
    C & Objective-C

    View full-size slide

  30. Language.C.Inline
    dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <-
    putStr urlData
    [NSString
    stringWithContentsOfURL:
    [NSURL URLWithString:urlString]
    encoding:NSUTF8StringEncoding
    error:NULL]
    [cexp|
    |]
    quasiquoted Objective-C
    22
    Tuesday, 9 September 14
    * Inline Objective-C
    * We need to specify the types of marshalled values, because…
    * (a) GHC 7.8’s TH provides less type information and (b) we may want custom marshalling

    View full-size slide

  31. Language.C.Inline
    dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <-
    putStr urlData
    [NSString
    stringWithContentsOfURL:
    [NSURL URLWithString:urlString]
    encoding:NSUTF8StringEncoding
    error:NULL]
    [cexp|
    |]
    $(objc [’urlString :> ''String] $ ''String <:
    )
    inline Objective-C splice
    22
    Tuesday, 9 September 14
    * Inline Objective-C
    * We need to specify the types of marshalled values, because…
    * (a) GHC 7.8’s TH provides less type information and (b) we may want custom marshalling

    View full-size slide

  32. Language.C.Inline
    dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <-
    putStr urlData
    [NSString
    stringWithContentsOfURL:
    [NSURL URLWithString:urlString]
    encoding:NSUTF8StringEncoding
    error:NULL]
    [cexp|
    |]
    $(objc [’urlString :> ''String] $ ''String <:
    )
    inline Objective-C splice
    marshalled arguments
    22
    Tuesday, 9 September 14
    * Inline Objective-C
    * We need to specify the types of marshalled values, because…
    * (a) GHC 7.8’s TH provides less type information and (b) we may want custom marshalling

    View full-size slide

  33. Language.C.Inline
    dumpURL :: String -> IO ()
    dumpURL urlString = do
    urlData <-
    putStr urlData
    [NSString
    stringWithContentsOfURL:
    [NSURL URLWithString:urlString]
    encoding:NSUTF8StringEncoding
    error:NULL]
    [cexp|
    |]
    $(objc [’urlString :> ''String] $ ''String <:
    )
    inline Objective-C splice
    marshalled arguments
    marshalled result
    22
    Tuesday, 9 September 14
    * Inline Objective-C
    * We need to specify the types of marshalled values, because…
    * (a) GHC 7.8’s TH provides less type information and (b) we may want custom marshalling

    View full-size slide

  34. [cexp| |]
    $(objc [’urlString :> ''String] $ ''String <:
    )

    23
    Tuesday, 9 September 14
    * All the FFI code is generated automatically

    View full-size slide

  35. [cexp| |]
    $(objc [’urlString :> ''String] $ ''String <:
    )

    foreign import stringWithContentsOfURLCstub
    :: CString -> IO CString
    stringWithContentsOfURL :: String -> IO String
    stringWithContentsOfURL url =
    withCString url $ \urlC -> do
    resultC <-
    stringWithContentsOfURLCstub urlC
    result <- peek resultC
    free resultC
    return result
    generated
    23
    Tuesday, 9 September 14
    * All the FFI code is generated automatically

    View full-size slide

  36. “Isn’t this supposed
    to be a demo?”
    24
    Tuesday, 9 September 14
    * Run through https://github.com/mchakravarty/language-c-inline/tree/master/tests/objc/
    concept
    * make & execute

    View full-size slide

  37. Marshalling records
    type Point = (Float, Float)
    newtype Vector = Vector (Float, Float)
    data Particle = Particle
    { mass :: Float
    , loc :: Point
    , vel :: Vector
    , acc :: Vector
    }
    25
    Tuesday, 9 September 14
    * A common problem is exchanging data between Haskell and Objective-C.

    View full-size slide

  38. “How do we turn this
    into an object?”
    26
    Tuesday, 9 September 14
    * Run through https://github.com/mchakravarty/language-c-inline/tree/master/tests/objc/
    record
    * Make & run
    * Show generated Objective-C interface

    View full-size slide

  39. Embedding Haskell
    27
    Tuesday, 9 September 14
    * Run through https://github.com/mchakravarty/language-c-inline/tree/master/tests/objc/
    app
    * Make & run

    View full-size slide

  40. 28
    Tuesday, 9 September 14

    View full-size slide

  41. Language integration by
    language inlining
    https://github.com/mchakravarty/language-c-inline
    cabal install language-c-inline
    29
    Tuesday, 9 September 14
    * Lack of bridge saves a lot of work; instant access to new versions
    * Bridges require familiarity with native libraries already; inline code leverages that directly
    * Haskell types are automatically mapped to types of the inlined language

    View full-size slide

  42. Thank you!
    30
    Tuesday, 9 September 14

    View full-size slide

  43. Images from
    http://wikimedia.org
    http://openclipart.org
    GitHub repo
    https://github.com/mchakravarty/language-c-inline
    Megamax Modula-2 Screenshot by Dirk Steins
    31
    Tuesday, 9 September 14

    View full-size slide