Code Monkey home page Code Monkey logo

Comments (9)

simonbyrne avatar simonbyrne commented on August 18, 2024

I don't think there's going to be an easy solution that will work for all functions which utilise non-standard evaluation. For plot, I think it might be easier to create a macro that automatically generates labels:

macro rplot(x,y,args...)
    :(rcall(:plot,$x,$y,xlab=$(string(x)),ylab=$(string(y)),$args...))
end
julia> macroexpand(:(@rplot(x,sin(x))))
:(rcall(:plot,x,sin(x),xlab="x",ylab="sin(x)",()...))

from rcall.jl.

randy3k avatar randy3k commented on August 18, 2024

There is also a related issue when doing lm.
(PS: please checkout current master for DataFrame conversion)

using RCall
using RDatasets
mtcars = dataset("datasets", "mtcars");
rprint(rcall(:lm, "Disp~MPG", data=mtcars))

It returns

julia> rprint(rcall(:lm, "Disp~MPG", data=mtcars))

Call:
lm(formula = "Disp~MPG", data = structure(list(Model = c("Mazda RX4", 
"Mazda RX4 Wag", "Datsun 710", "Hornet 4 Drive", "Hornet Sportabout", 
"Valiant", "Duster 360", "Merc 240D", "Merc 230", "Merc 280", 
.
.
.
4L, 4L, 4L, 4L, 3L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 3L, 3L, 3L, 
3L, 3L, 4L, 5L, 5L, 5L, 5L, 5L, 4L), Carb = c(4L, 4L, 1L, 1L, 
2L, 1L, 4L, 2L, 2L, 4L, 4L, 3L, 3L, 3L, 4L, 4L, 4L, 1L, 2L, 1L, 
1L, 2L, 2L, 4L, 2L, 1L, 2L, 2L, 4L, 6L, 8L, 2L)), .Names = c("Model", 
"MPG", "Cyl", "Disp", "HP", "DRat", "WT", "QSec", "VS", "AM", 
"Gear", "Carb"), class = "data.frame", row.names = c(NA, 32L)))

Coefficients:
(Intercept)          MPG  
     580.88       -17.43  

from rcall.jl.

simonbyrne avatar simonbyrne commented on August 18, 2024

Eesh, that's messy.

from rcall.jl.

randy3k avatar randy3k commented on August 18, 2024

This may be a better way to resolve the lazy evaluation problem. It uses R_mkEVPROMISE to create a promise object first.

using RCall
RCall.rgui_start()

macro promise(x)
    sym = Expr(:quote, symbol(string(x)))
    quote
        RCall.preserve(sexp(ccall((:R_mkEVPROMISE,libR),Ptr{Void},(Ptr{Void},Ptr{Void}), sexp($sym), sexp($x))))
    end
end

x = linspace(0,pi,10)
rcall(:plot, (@promise x), (@promise sin(x)))

EDIT:
This workaround can correctly handled substitute but not match.call(). Therefore, it doesn't solve the lm issue.

reval("""
       f <- function(x) substitute(x)
       g <- function(x) match.call()
""");
rprint(rcall(:f, @promise x))  
# x
rprint(rcall(:g, @promise x))
# g(x = c(0, 0.111111111111111, 0.222222222222222, 0.333333333333333, 
# 0.444444444444444, 0.555555555555556, 0.666666666666667, 0.777777777777778, 
# 0.888888888888889, 1))

from rcall.jl.

simonbyrne avatar simonbyrne commented on August 18, 2024

Nice! That's really cool.

Do you know what is the difference between R_mkEVPROMISE and R_mkEVPROMISE_NR?

from rcall.jl.

randy3k avatar randy3k commented on August 18, 2024

It is used to disabled reference counting so that gc() will collect the corresponding memory. In default, R is using a different way to do reference counting. It is not relevant unless R is complied with SWITCH_TO_REFCNT.

from rcall.jl.

randy3k avatar randy3k commented on August 18, 2024

I am trying an lazy macro with the hope of handling non-standard evaluations. The idea is to copy the Julia objects to R in a sandbox environment. And then evaluate the function call in that environment.

macro lazy(expr)
    blk = Expr(:block)
    cleanup = Any[]
    push!(blk.args,:(env = newEnvironment(rGlobalEnv)))
    (expr.head == :call && expr.args[1] == :rcall) || error("expect rcall(f, args...)")
    args = copy(expr.args)
    shift!(args)
    for (i,a) in enumerate(args)
        if typeof(a) == Symbol
            push!(blk.args,:(env[$(QuoteNode(a))] = sexp($(esc(a)))))
            args[i] = QuoteNode(a)
            push!(cleanup,:(env[$(QuoteNode(a))] = rNilValue))
        elseif typeof(a) == Expr && a.head == :kw && typeof(a.args[2]) == Symbol
            value = a.args[2]
            push!(blk.args,:(env[$(QuoteNode(value))] = sexp($(esc(value)))))
            args[i].args[2] = QuoteNode(value)
            push!(cleanup,:(env[$(QuoteNode(value))] = rNilValue))
        else
            args[i] = :($(esc(a)))
        end
    end
    ret_call = :(ret = reval(rlang_p(),env))
    append!(ret_call.args[2].args[2].args, args)
    push!(blk.args, ret_call)
    append!(blk.args, cleanup)
    push!(blk.args,:(ret))
    blk
end

With this macro, I get this

julia> using RCall

julia> rmtcars = dataset("datasets", "mtcars");

julia> @lazy rcall(:lm, reval("as.formula('HP~MPG')"), data=rmtcars)
RCall.RObject{RCall.VecSxp}

Call:
lm(formula = HP ~ MPG, data = rmtcars)

Coefficients:
(Intercept)          MPG  
     324.08        -8.83  

from rcall.jl.

simonbyrne avatar simonbyrne commented on August 18, 2024

I think we should be able to do something like that inside the @R_str macro.

My only question is if this breaks other functions which use this (e.g. update)?

from rcall.jl.

randy3k avatar randy3k commented on August 18, 2024

I think the purposes of @R_str and the @lazy macro are little bit different.

@R_str parses string to expressions. We need to evaluate expressions under the global environment to make sure that expressions like x <- 1 or a[3] <- 2 return expected results. If we create a sandbox environment to evaluate x<-1, it only changes a local variable x and the value the global variable x is kept untouched.

On the other hand, @lazy takes only function calls as input. It does not touch any R global variables, it means that @lazy calls could be separated and sandboxed.

from rcall.jl.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.