Avi Grant
Avi Grant

Reputation: 13

Creating Custom Function in R - have two connected arguments in the function where at least one of the arguments is required

I am trying to create a function in R that creates a geometric sequence based on the inputs of 'start' (the starting value), 'by' (the common ratio) and two arguments that depending on which one is given decides how the sequence is generated either;

this is the code I have written so far:

geomSeq <- function(start, by, times = log(end/start, base = by), 
                    end = start * by^(times)){
  start * by^(0:times)
}

Note that I have defined the default arguments of 'times' and 'end' by each other, so if both are missing then I get a recursion error. I want to throw an error if both of these arguments are missing, without the horrible recursion error popping up.

So I was wondering if there is a better way of defining two arguments where either of them, but at least one of them, can be inputted.

This was my attempt at doing this myself;

geomSeq <- function(start, by, times = log(end/start, base = by), 
                            end = start * by^(times)){
  if(is.null(times) && is.null(end)) stop("either 'times' or 'end' argument must be given")
  start * by^(0:times)
}

and when I tested this and ran the function without the times or end arguments this is the error that I got, which I don't want to show up.

> geomSeq(start = 10, by = 10)
Error in geomSeq(start = 10, by = 10) : 
  promise already under evaluation: recursive default argument reference or earlier problems?

I also tried to remove the arguments from within the function specification

geomSeq <- function(start, by, times = log(end/start, base = by), end = NULL){
  if(is.null(times) && is.null(end)) stop("either 'times' or 'end' argument must be given")
  if(is.null(times)){
    times <- log(end/start, base = by)
    result <- start * by^(0:times)
  } else{
    result <- start * by^(0:times)
  }
  return(result)
}

but I wasn't sure how to get this to work either.

Upvotes: 1

Views: 30

Answers (1)

Gregor Thomas
Gregor Thomas

Reputation: 146020

Use missing() not is.null(). Your arguments aren't NULL, they are defined recursively. And this is what missing() is for.

geomSeq <- function(start, by, times = log(end/start, base = by), 
                            end = start * by^(times)){
  if(missing(times) && missing(end)) stop("either 'times' or 'end' argument must be given")
  start * by^(0:times)
}
geomSeq(start = 10, by = 10)
# Error in geomSeq(start = 10, by = 10) : 
#   either 'times' or 'end' argument must be given

Upvotes: 2

Related Questions