-
Calling R in Haskell
2016-09-03
SourceThis 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???sprint
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