Ben
Ben

Reputation: 1556

Can you create an R function that calls using a prefix and suffix (operating like brackets)?

I have read about prefix functions and infix functions on Hadley Wickham's Advanced R website. I would like to know if there is any way to define functions that are called by placing a prefix and suffix around a single argument, so that the prefix and suffix operate like brackets. Is there any way to create a function like this, and if so, how do you do it?


An example for formulation: In order to give a specific example for formulation, suppose you have an object char that is a character string. You want to create a function that is called on a character string using the prefix _# and suffix #_ and the function adds five dashes to the front of the character string. If programmed successfully, it would operate as shown below.

char
[1] "Hello"

_#char#_
[1] "-----Hello"

Upvotes: 0

Views: 636

Answers (2)

MrFlick
MrFlick

Reputation: 206566

Writing a simple function seems like a more R-like solution. If terseness is a priority, then maybe something like

._ <- function(x) paste0("-----", x)

._("hello")
# [1] "-----hello"

Or if you wanted something more bracket-like

.. <- structure(list(NULL), class="dasher")
`[.dasher` <- function(a, x) paste0("-----", x)

..["hello"]
# [1] "-----hello"

Another way to use a custom class would be to redefine the - operator to paste that value in front of the string. For example

literal <- function(x) {class(x)<-"literal"; x}
`-.literal` <- function(e1, e2) {literal(paste0("-", unclass(e1)))}
print.literal <- function(x) print(unclass(x))

Then you can do

val <- literal("hello")
-----val
# [1] "-----hello"
---val
# [1] "---hello"

So here the number of - you type is the number you get in the output.

You can get creative/weird with syntax, but you need to make sure whatever symbols you come up with can be parsed by the parser otherwise you are out-of-luck.

Upvotes: 3

Allan Cameron
Allan Cameron

Reputation: 174536

There is a way to do this as long as your special operator takes a particular form, that is .%_% char %_%. . This is because the parser will interpret the dot as a variable name. If we use non-standard evaluation, we don't need the dot to actually exist, and we only need to use this as a marker for opening and closing our special operator. So we can do something like this:

`%_%` <- function(a, b) 
{
   if((deparse(match.call()$a) != ".") +
      (deparse(match.call()$b) != ".") != 1)
     stop("Unrecognised SPECIAL")
   
  if(deparse(match.call()$a == "."))
    return(`attr<-`(b, "prepped", TRUE))
  
  if(attr(a, "prepped"))
    return(paste0("-----", a))
  
  stop("Unrecognised SPECIAL")
}

.%_% "hello" %_%.
#> [1] "-----hello"

However, this is a weird thing to do in R. It's not idiomatic and uses more keystrokes than a simple function call would. It would also very likely cause unpredictable problems in places where non-standard evaluation is used. This is really just a demo to show that it can be done. Not that it should be done.

Upvotes: 4

Related Questions