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

Foreign Inline Code in Haskell (Haskell Symposi...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

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.

Avatar for Manuel Chakravarty

Manuel Chakravarty PRO

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