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.

2cc5323ccdfc09b921f1be34b3d78a69?s=128

Manuel Chakravarty

September 05, 2014
Tweet

Transcript

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

    2 Tuesday, 9 September 14 » Imagine you want to

    write a great new app in Haskell!
  3. 3.

    2 Tuesday, 9 September 14 » Imagine you want to

    write a great new app in Haskell!
  4. 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.
  5. 5.

    “Problem solved?” 4 Tuesday, 9 September 14 » Does that

    solve the problem of language interoperability? » Let me explain that at an example...
  6. 6.

    “Problem solved?” No! 4 Tuesday, 9 September 14 » Does

    that solve the problem of language interoperability? » Let me explain that at an example...
  7. 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.
  8. 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.
  9. 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.]
  10. 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
  11. 11.

    C➙Haskell c2hs A case study GTK+ 8 Tuesday, 9 September

    14 * c2hs: automation for bridging C libraries to Haskell <https://hackage.haskell.org/package/ c2hs> * Implements large parts of a C compiler front-end * Bridge for the cross-platform Gnome GUI library GTK+ <http://projects.haskell.org/ gtk2hs/>
  12. 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
  13. 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
  14. 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
  15. 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
  16. 18.

    “Interoperability is an old problem — maybe an old solution

    can help?” 14 Tuesday, 9 September 14
  17. 19.

    15 Tuesday, 9 September 14 * Modula-2 with inline 68000

    assembly * Assembly code can symbolically refer to Modula-2 entities (e.g., variables)
  18. 20.

    15 Tuesday, 9 September 14 * Modula-2 with inline 68000

    assembly * Assembly code can symbolically refer to Modula-2 entities (e.g., variables)
  19. 21.

    15 Tuesday, 9 September 14 * Modula-2 with inline 68000

    assembly * Assembly code can symbolically refer to Modula-2 entities (e.g., variables)
  20. 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?
  21. 23.

    HASKELL WORKSHOP 2002 HASKELL WORKSHOP 2007 17 Tuesday, 9 September

    14 » We use Template Haskell's general quasi-quotation support…
  22. 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.
  23. 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.
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 34.

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

    … 23 Tuesday, 9 September 14 * All the FFI code is generated automatically
  31. 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
  32. 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
  33. 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.
  34. 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
  35. 39.

    Embedding Haskell 27 Tuesday, 9 September 14 * Run through

    https://github.com/mchakravarty/language-c-inline/tree/master/tests/objc/ app * Make & run
  36. 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