Getting objects in a situation where their name matters - r

I have a list of functions that I'd like to make documentation for. My question is not about how to do this, but it provides a convenient example of something I'm curious about.
prompt takes a function and a character string as arguments, and writes a help file on that function to the file represented by the character string path. In looping over the files, using prompt(f,filename=...) doesn't work since f is of type character. I tried get(f), which pulls the function out just fine, but doesn't give prompt enough information to work with (see below). So how do I force a character element to return the whole object not just the function that it names?
files <- c("current.market","current.portfolio.bond","fund","genAccount","genHistory.market","history.market","maRketSim.version","summary.vasicek.discrete","vasicek.discrete")
for(f in files) {
prompt( get(f), filename=paste("c:/myproject/man/",f,".Rd",sep="") )
}
Error in prompt.default(get(f), filename = paste("F:/Documents/R-projects/maRketSim/man/", :
cannot determine a usable name

?prompt tells us that
Arguments:
object: an R object, typically a function for the default method.
Can be ‘missing’ when ‘name’ is specified.
So I think prompt() already does what you want:
> prompt(name = "print", filename = "print.Rd")
Created file named 'print.Rd'.
Edit the file and move it to the appropriate directory.
Which does produce the relevant Rd file:
> writeLines(readLines("~/print.Rd"))
\name{print}
\alias{print}
%- Also NEED an '\alias' for EACH other topic documented here.
\title{
%% ~~function to do ... ~~
}
\description{
%% ~~ A concise (1-5 lines) description of what the function does. ~~
}
\usage{
print(x, ...)
}
%- maybe also 'usage' for other objects documented here.
\arguments{
\item{x}{
%% ~~Describe \code{x} here~~
....
I should add, that get("foo") does return the actual function, it is just the way that prompt() is coded that it can't work with an anonymous function as returned by get().

Related

ifelse and append not working within a function

I want to distribute the names of files in two different vectors. If they exist, they should go to existing_files and if not, they should go to missing_files.
existing_files <- ""
missing_files <- ""
f1 <- function(file_name){
if (any(file_name == vector_of_file_names)) {
existing_files <- append(existing_files, file_name)
} else {
missing_files <- append(missing_files, file_name)
}
}
f1("file1")
Executing "file1" does not work and i don't get any warning or error. Why is that? If i remove "existing_files <-" and "missing_files <-" in the function, i would get the correct result in the console. But i need it stored in the global environment.
A bit more information on what i am trying to solve here:
I am scanning the folder i am working with for file names i have stored in "vector_of_file_names". I just wanna know, if all the files i need are in that folder or not. I do that with list.files, which gives me all the files. Then i compare those files to "vector_of_file_names". The result is what is seen in my question. I want two vectors that list the files (that i want in that folder) according to their existence in that folder.
existing_files and missing_files are in the global scope. They can't be changed within the scope of your function without super-assignment <<-
existing_files <- ""
missing_files <- ""
f1 <- function(file_name){
if (any(file_name == existing_files)) {
existing_files <<- append(existing_files, file_name)
} else {
missing _files <<- append(missing_files, file_name)
}
}
f1("file1")
Can you give a little more context on the problem you are trying to solve? I don't see anything in your code that actually tests for the "existence" of files, only the state of the vector existing_files.
It is unusual design choice to have a function which acts on a single object at a time and then potentially modifies state in one of multiple external objects depending on the result. Yes, you can "solve" your problem using exotic methods like out of superassignment (where objects in others scopes are modified as a side effect of your function) but your code will quickly become hard to reason about.

Changing imported R function globally

I want to globally add a parameter to a function after import. So in future function calls the function should be always called with the set parameter.
In this case, I want to add the function parameter in_schema("abc") to the function tbl from dplyr.
Normally, I would use the source code and modify the function parameters, save and source it. But in this case, I am already failing to get a proper source code file.
getAnywhere("tbl.DBIConnection")
A single object matching 'tbl.DBIConnection' was found
It was found in the following places
registered S3 method for tbl from namespace dplyr
namespace:dplyr
with value
function (src, from, ...)
{
check_dbplyr()
tbl(dbplyr::src_dbi(src, auto_disconnect = FALSE), from = from,
...)
}
How could I modify the tbl-function (in a script file) so future calls always use a certain Scheme?
like so:
tbl(connection, table, in_schema("abc"))
without having to provide the in_schema parameter all the time.
Don't copy and modify the function, it's messy, do something like this instead :
tbl_abc <- function(src, from, ...){
tbl(src, in_schema("abc", from), ...)
}
btw tbl(connection, table, in_schema("abc")) is improper syntax, in_schema("abc") needs a second argument, and it's passed to the ..., which are not used by tbl.DBIConnection()

Why does rm inside a function not delete objects?

rel.mem <- function(nm) {
rm(nm)
}
I defined the above function rel.mem -- takes a single argument and passes it to rm
> ls()
[1] "rel.mem"
> x<-1:10
> ls()
[1] "rel.mem" "x"
> rel.mem(x)
> ls()
[1] "rel.mem" "x"
Now you can see what I call rel.mem x is not deleted -- I know this is due to the incorrect environment on which rm is being attempted.
What is a good fix for this?
Criteria for a good fix:
The caller should not have to pass the environment
The callee (rel.mem) should be able to determine the environment by using an R language facility (call stack inspection, aspects, etc.)
The interface of the function rel.mem should be kept simple -- idiot proof: call rel.mem -- then rel.mem takes it from there -- no need to pass environments.
NOTES:
As many commenters have pointed out that one easy fix is to pass the environment.
What I meant by a good fix [and I should have clarified it] is that the callee function (in this case rel.mem) is able to calculate/find out the environment when the caller was referring to and then remove the object from the right environment.
The type of reasoning in "2" can be done in other languages by inspecting the call stack -- for example in Java I would throw a dummy exception -- catch it and then parse the call stack. In other languages still I could use Aspect Oriented techniques. The question is can something like that be done in R?
As one commenter has suggested that there may be multiple objects with the same name and thus the "right" environment is meaningless -- as I've stated above that in other languages it is possible (sometimes with some creative trickery) to interpret the call-stack -- this may not be possible in R
As one commenter has suggested that rm(list=nm, envir = parent.frame()) will remove this from the parent environment. This is correct -- however I'm looking for something that will work for an arbitrary call depth.
The quick answer is that you're in a different environment - essentially picture the variables in a box: you have a box for the function and one for the Global Environment. You just need to tell rm where to find that box.
So
rel_mem <- function(nm) {
# State the environment
rm(list=nm, envir = .GlobalEnv )
}
x = 10
rel_mem("x")
Alternatively, you can use the pos argument, e.g.
rel_mem <- function(nm) {
rm(list=nm, pos=1 )
}
If you type search() you will see a vector of environments, the global is number 1.
Another two options are
envir = parent.frame() if you want to go one level up the call stack
Use inherits = TRUE to go up the call stack until you find something
In the above code, notice that I'm passing the object as a character - I'm passing the "x" not x. We can be clever and avoid this using the substitute function
rel_mem <- function(nm) {
rm(list = as.character(substitute(nm)), envir = .GlobalEnv )
}
To finish I'll just add that deleting things in the .GlobalEnv from a function is generally a bad idea.
Further resources:
Environments:http://adv-r.had.co.nz/Environments.html
Substitute function: http://adv-r.had.co.nz/Computing-on-the-language.html#capturing-expressions
If you are using another function to find the global objects within your function such as ls(), you must state the environment in it explicitly too:
rel_mem <- function(nm) {
# State the environment in both functions
rm(list = ls(envir = .GlobalEnv) %>% .[startsWith(., "plot_")], envir = .GlobalEnv)
}

what is wrong with this list naming assignment?

Folks -
I'm going to keep my code here brief, as I think to those more familiar with R, it will be obvious. I am trying to use a function (not my own) that requires I feed it a list of named lists of parameters. I am having trouble naming the lists via a function I wrote to create each list element. Here is my function:
# for invoking grts
stratumdesign<- function(ns, points, oversamp) {
stratumname<-as.character(ns)
print("from function")
print(stratumname)
designlist<-list(ns=c(panel=points, seltype="Equal", over=oversamp))
return(designlist)
}
.. I have tried both having the function call have ns be the integer it is in the originating code, or be passed as a character. Neither work. What I'm illustrating here to myself w/in the function is that ns gets properly passed to the function, but the resulting list returned is always named "$ns" when I want it to be the value passed AS ns! What on Earth am I doing wrong, here?
Since this deserves an actual answer, not just a comment...
Try something more like this:
stratumdesign<- function(ns, points, oversamp) {
print("from function")
print(stratumname)
designlist<-list(c(panel=points, seltype="Equal", over=oversamp))
names(designlist) <- as.character(ns)
return(designlist)
}

Get variables that have been created inside a function

I have created a function (which is quite long) that I have saved in a .txt file.
It works well (I use source(< >) to access it).
My problem is that I have created a few variables in that function
ie:
myfun<-function(a,b) {
Var1=....
Var2=Var1 + ..
}
Now I want to get those variables.
When I include return() inside the function, its fine: the value comes up on the screen, but when I type Var1 outside the function, I have an error message "the object cannot be found".
I am new to R, but I was thinking it might be because "myfun" operates in a different envrionment than the global one, but when I did
environment()
environment: R_GlobalEnv>
environment(myfun1)
environment: R_GlobalEnv>
It seems to me the problem is elsewhere...
Any idea?
Thanks
I realize this answer is more than 3 years old but I believe the option you are looking for is as follows:
myfun <- function(a,b) {
Var1 = (a + b) / 2 # do whatever logic you have to do here...
Var2 <<- Var1 + a # then output result to Global Environment with the "<<-" object.
}
The double "<<-" assignment operator will output "Var2" to the global environment and you can then use or reference it however you like without having to use "return()" inside your function.
If you want to do it in a nice way, write a class and than provide a print method. Within this class it is possible to return variables invisible. A nice book which covers such topics is "The Art of R programming".
An easy fix would be save each variable you need later on an list and than return a list
(as Peter pointed out):
return(list(VAR1=VAR1, .....))

Resources