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.
  2. 2 Tuesday, 9 September 14 » Imagine you want to

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

    write a great new app in Haskell!
  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. “Problem solved?” 4 Tuesday, 9 September 14 » Does that

    solve the problem of language interoperability? » Let me explain that at an example...
  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. 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. 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. 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. 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. 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. 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. “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. 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. 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. “Interoperability is an old problem — maybe an old solution

    can help?” 14 Tuesday, 9 September 14
  17. 15 Tuesday, 9 September 14 * Modula-2 with inline 68000

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

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

    assembly * Assembly code can symbolically refer to Modula-2 entities (e.g., variables)
  20. “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. HASKELL WORKSHOP 2002 HASKELL WORKSHOP 2007 17 Tuesday, 9 September

    14 » We use Template Haskell's general quasi-quotation support…
  22. 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. 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. 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. 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. 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. 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. 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. 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. [cexp| |] $(objc [’urlString :> ''String] $ ''String <: )

    … 23 Tuesday, 9 September 14 * All the FFI code is generated automatically
  31. [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. “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. 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. “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. Embedding Haskell 27 Tuesday, 9 September 14 * Run through

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