tweag / HaskellR

The full power of R in Haskell.

Home Page:https://tweag.github.io/HaskellR

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to best access R values in Haskell

skeydan opened this issue · comments

Hi,
sorry I'm back with 2 stupid questions (oops: 1 question ;-) I just solved 1 thing myself ;-))
I want to make up simple examples of interoperability (besides printing and plotting), that is, I want to get at the R values for further processing (the values, not the pointers).

From the docs (

https://tweag.github.io/HaskellR/docs/how-to-analyze-r-values.html

), I don't really get how to do this (copy-pasting the example gave a compiler error), so I've looked through the examples, and the one thing I got to compile was from adapting the FFT example to my (simpler) use case, like this

get_normals :: Double -> R s [Double]
get_normals n = do
   H.dynSEXP <$> [r| rnorm(n_hs) |]
result <- H.runRegion $ get_normals 4
result

But honestly I have no idea if this is an adequate solution for my (very simple) use case...
Could you please tell me what's the preferred way to do this?
Many thanks in advance!

There are several approaches, which of which is useful in different scenarios. Let me add some context first.

We have 2 types for the R values SomeSEXP s and SEXP t s. Former stands for variable of any type (that we do not know at compilation time), latter stands for the variable of the type we know in advance. SomeSEXP basically stands for all of the variables returned from the R computations due to it's dynamic nature. For most of the accesses (when you know the type you want) you want to go from SomeSEXP to SEXP, and there is a way to go using cast function it takes the parameter of the type you want and returns you either SEXP or fails at runtime, if type is different.

In order to go from the SEXP to haskell value you can choose to use Literal instance, that allow you to convert R value to the haskell one using fromSEXP. However it may be a bit ineffective as it creates new haskell value on Haskell heap for all Haskell types.

In addition there are some helpers:

  • If you have SomeSEXP you may choose to use fromSomeSEXP that will cast value first.
  • If you are ok with dynamic change of types, i.e. you are of with converting ints to doubles implicitly then you may use dynSEXP that instead of failing will try it's best effort to convert value to accessible type.

However you do not always know the type of the variable, for that case you have unSomeSEXP inside unSomeSEXP function you have a variable with type that you don't know. And you can analyze it using hexp API, this allow you to check structural properties of your variables. Just write:

unSomeSEXP ss $ \s -> case hexp s of
  Int v -> ...
  _

Third way is just introduced parser API this API is not released yet, but it allow you to write Applicative parser for your values, and have a nice API to get attributes like class names, dimensions and other.
It's not been covered in manual yes, but if you need examples or solution to your problem - feel free to ask.

About usage:

  1. fromSEXP is the simples way but it may not be effective, and do not allow you to access attributes at all.
  2. hexp API is the most efficient but very low level, in most cases you'll need to analyse structure manually and know R internals very well.
  3. parser most reasonable API (in my taste) but not yet totally covered.
  4. you can combine approaches like in your example above, when you use quasi-quote to get basic types from the R value, and then convert it to haskell using fromSEXP.

In my taste example above is quite ok. Basically it consists of:

  H.dynSEXP <$> [r| .. |]

get value, by trying to dynamically map that to the type required for you. And actuall call of the method

H.runRegion $ get_normals 4

that doesn't look too terrible..

Thank you very much, that was very helpful! I'll leave it as is then :-)

have a nice API to get attributes like class names, dimensions and other

This sounds very promising indeed! I won't use it this time, but keep in mind for later...

Best,
Sigrid