Quosure Tutorial

I've added another tutorial. This one is about the structure of a quosure.

http://r.danal.com/tutorials/QuosureTree.html

It is some supporting information for the next tutorial I am working on about using quosures to program on the language.

4 Likes
  • node_car() and node_cdr() are /very/ low level accessors that can easily make R crash. They are for experts only and mostly provided as a way of prototyping C code in R. I think you should mention the risks to the readers of your blog.

  • It is preferable to use accessors like get_expr() and get_env() to access the components of quosures. They are currently implemented as formulas but might not be in the future. Accessing the expression with f_rhs() will be soft-deprecated in the next version.

Good to know f_rhs is being deprecated. I had wondered why f_rhs and get_expr returned the same thing. I'll switch to get_expr in the next tutorial and explain why. BTW I used f_rhs because it fits in the story better given that a quosure is a one sided formula.

I think I can do some of the things I want to do with lang_head and lang_tail but I don't know of a way to modify an expression without mut_nod_car and friends, is there one?. But I was going to put a warning on the node_ and mut_ functions in the next tutorial on these anyhow... they can do a great job of crashing a session.

How do you know when a function is scheduled for deprecation? The doc's don't seem to be kept up to date with that kind of info.

Thanks @lionel for the info

This will be indicated in the NEWS. Note that it's not f_rhs() as a whole that will be deprecated, it will continue to work for regular formulas.

Just extract the expression from the quosure with get_expr() and modify that expression the usual way (e.g. with the subset-assign operators). When the new expression is ready use set_expr() to update the quosure or use new_quosure() to create a new one (in which case don't forget to supply the environment where the symbols mentioned in the expression are defined).

Ahh, I didn' t know about the NEWS file in github, thanks. But the current one doesn't mention anything about f_rhs. Maybe it's implied by some of the notes in it.

I'll have to try out get_/set_ expr. If I understand things correctly I can see how lang_tail/head get_/set_expr can replace the node_ and mut_ functions.

I wouldn't use lang_head() and lang_tail() at all. While they are safer than node_car() and node_cdr(), they are unnecessarily low level for most R metaprogramming work. As for f_rhs() new behaviour it is not mentioned in the NEWS yet because it's not been (soft-)deprecated yet.

But without lang_head/tail how do you traverse (i.e. parse) the trees in the expression in the quosure?. The only alternative I see is to parse the raw text of the expression which isn't really possible.

For example if I want to know the operator the expression uses?

You use subsetting operators.

The subsetting ops do a nice job of parsing out the expression so I can see their use when metaprogamming is just analyzing an expression and then goes and builds a new one or just executes some code based on the analysis.

But I don't see how, even with set_expr, you can modify an existing expression, for example change the + in the expression 1 + 2 to a -. It seems like mut_node_ and friends are the only way to do that.

Also the strings you get with get_expr and subsetting are not formatted all that nicely and need some addition processing to make the expression look like the expression.

But maybe I am missing something here so I'll do a bit more digging.

Now that I've dug into parsing an expression by subsetting I can see that it works. It does produce a different object model that parsing by traversing node/car/cdr but that's not a problem.

In the end it's less work to parse with subset than node/car/cdr.

Edited.... it's easy to make mod's deep in the hierarcy

I had seen the use of subsetting mentioned in the doc's a number of times but I didn't really grasp how to used until you mentioned it.

So it looks like I can do everything I want without having to use node_ or mut_node functions.

Thanks @lionel for your comments.

Now try call[-1] <- lapply(call[-1], my_recursive_function).

2 Likes

Thanks for the tutorial! I have a couple questions.

It sounds like a quosure should be thought of as a wrapper for an R expression. What is the motivation for using this wrapper? (Maybe you are planning to address this in your next tutorial.)

When you say that a quosure mimics the behavior of other types of R objects (such as a formula), is this the same as saying that the quosure class inherits the behavior of the formula class? If not, what is the difference between mimicking and inheritance?

Hi danr, thanks for the tutorial! Do you use twitter? If yes, what's your handle? I'd like to follow you to get blog updates.

The is a new tutorial coming out shortly that covers that and more

my twitter handle is @d114