1. Calling R in Haskell

    2016-09-03
    Source

    This is a demo of the inline-R Haskell library, allowing to call R from Haskell.

    In order to call R in GHCi, you have to run this preamble before:

    :set -XDataKinds
    :set -XGADTs
    :set -XPartialTypeSignatures
    :set -XOverloadedLists
    :set -XQuasiQuotes
    :set -XScopedTypeVariables
    :set -XTemplateHaskell
    :set -XViewPatterns
    import Data.Int (Int32)
    import H.Prelude.Interactive
    import qualified Language.R.Instance as R
    R.initialize R.defaultConfig
    

    Therefore, since I use knitr+ghcscriptrender to write this article, I save the following code in a file Rpreamble.hs:

    import Data.Int (Int32)
    import H.Prelude.Interactive
    import qualified Language.R.Instance as R
     
    main :: IO()
    main = do
      R.initialize R.defaultConfig
      return()
    

    And now I can call R like this:

    > :load Rpreamble.hs
    > :set -XTemplateHaskell -XQuasiQuotes -XScopedTypeVariables -XDataKinds -XGADTs -XPartialTypeSignatures -XOverloadedLists -XViewPatterns
    > -- perform 1+1 in R:
    > x <- [r| 1 + 1 |]
    > fromSomeSEXP x :: Double
    2.0
    > -- integers from 1 to 3:
    > x <- [r| 1:3 |]
    > fromSomeSEXP x :: [Int32]
    [1,2,3]
    

    One can run several commands in [r| ...|]:

    > :load Rpreamble.hs
    > :set -XTemplateHaskell -XQuasiQuotes -XScopedTypeVariables -XDataKinds -XGADTs -XPartialTypeSignatures -XOverloadedLists -XViewPatterns
    > -- separate with a semi-colon:
    > x <- [r| a <- 2; 3+a |]  
    > fromSomeSEXP x :: Double
    5.0
    > -- or multiline:
    > :{
    > x <- [r| a <- 2
    > 3+a |]
    > :}
    > fromSomeSEXP x :: Double
    5.0
    

    One can load and use a package:

    > :load Rpreamble.hs
    > :set -XTemplateHaskell -XQuasiQuotes -XScopedTypeVariables -XDataKinds -XGADTs -XPartialTypeSignatures -XOverloadedLists -XViewPatterns
    > -- load and use the jsonlite package
    > :{
    > x <- [r| library(jsonlite)
    > dat <- data.frame(name=c('Joe', 'Bill'), age=c(23,40))
    > toJSON(dat) |]
    > :}
    > fromSomeSEXP x :: String
    "[{\"name\":\"Joe\",\"age\":23},{\"name\":\"Bill\",\"age\":40}]"
    > -- But I prefer this way sometimes:
    > :{
    > x <- [r| dat <- data.frame(name=c('Joe', 'Bill'), age=c(23,40))
    > jsonlite::toJSON(dat) |]
    > :}
    > fromSomeSEXP x :: String
    "[{\"name\":\"Joe\",\"age\":23},{\"name\":\"Bill\",\"age\":40}]"
    

    The most interesting feature is the ability to pass a Haskell variable in R:

    > :load Rpreamble.hs
    > :set -XTemplateHaskell -XQuasiQuotes -XScopedTypeVariables -XDataKinds -XGADTs -XPartialTypeSignatures -XOverloadedLists -XViewPatterns
    > -- 
    > let a = 2::Double
    > x <- [r| 3 + a_hs|]
    > fromSomeSEXP x :: Double
    5.0
    

    The p function displays the output of R???s print function:

    > :load Rpreamble.hs
    > :set -XTemplateHaskell -XQuasiQuotes -XScopedTypeVariables -XDataKinds -XGADTs -XPartialTypeSignatures -XOverloadedLists -XViewPatterns
    > -- print
    > p [r| 1+1 |]
    [1] 2
    

    The jsonlite package allows to get arrays and lists from Haskell:

    > :load Rpreamble.hs
    > :set -XTemplateHaskell -XQuasiQuotes -XScopedTypeVariables -XDataKinds -XGADTs -XPartialTypeSignatures -XOverloadedLists -XViewPatterns
    > -- an array:
    > let a = [[1,2],[3,4]]::[[Int]]
    > let b = show a
    > p [r| jsonlite::fromJSON(b_hs) |]
         [,1] [,2]
    [1,]    1    2
    [2,]    3    4
    > -- a list:
    > let a = [[1,2],[3,4,5]]::[[Int]]
    > let b = show a
    > p [r| jsonlite::fromJSON(b_hs) |]
    [[1]]
    [1] 1 2
    
    [[2]]
    [1] 3 4 5
    
    

    And dataframes, with the help of the aeson library.

    > :load Rpreamble.hs
    > :set -XTemplateHaskell -XQuasiQuotes -XScopedTypeVariables -XDataKinds -XGADTs -XPartialTypeSignatures -XOverloadedLists -XViewPatterns
    > -- get the JSON representation of a dataframe:
    > import Data.Aeson
    > import GHC.Generics
    > :set -XOverloadedStrings -XDeriveGeneric
    > data Person = Person { name :: String, age :: Int } deriving (Show, Generic)
    > instance ToJSON Person
    > let persons = [Person "Joe" 21, Person "Bill" 40]::[Person]
    > encode persons
    "[{\"age\":21,\"name\":\"Joe\"},{\"age\":40,\"name\":\"Bill\"}]"
    > -- pass it to R:
    > import qualified Data.Text.Lazy.Encoding as T
    > import qualified Data.Text.Lazy as T
    > let b = T.unpack $ T.decodeUtf8 $ encode persons
    > p [r| jsonlite::fromJSON(b_hs) |]
      age name
    1  21  Joe
    2  40 Bill