Quosure tree diagram

No questions, I was just :grin: to get this to work.

Since I discovered DiagrammeR I've been able to generate a node diagram of a quosure. The one below is for the quosure of this expression:

a * fn(b, c, 1:3) + c * (d + w)

Crossed lines isn't a good thing but eventually I'll find away to pretty things up...

I'll be using this in my next tutorial.

8 Likes

+1 for introducing me to DiagrammR :blush:

Something similar in the console is pryr::ast()

pryr::ast(a * fn(b, c, 1:3) + c * (d + w))
#> \- ()
#>   \- `+
#>   \- ()
#>     \- `*
#>     \- `a
#>     \- ()
#>       \- `fn
#>       \- `b
#>       \- `c
#>       \- ()
#>         \- `:
#>         \-  1
#>         \-  3
#>   \- ()
#>     \- `*
#>     \- `c
#>     \- ()
#>       \- `(
#>       \- ()
#>         \- `+
#>         \- `d
#>         \- `w

I learned loads from Hadley's explanation of this in Advanced R. Thanks to Jenny Bryan for suggesting it.

1 Like

These days you're better off with lobstr::ast() which I'm using in the 2nd ed of advanced R: https://adv-r.hadley.nz/expressions

5 Likes

Where can the lobstr package be installed from. In R Studio I tried installing it but it doesn't seem to be on CRAN.

It's on GitHub, so to install it use devtools::install_github("hadley/lobstr").

2 Likes

Dan it seems you are using the term "quosure" in place of "expression". This is not right as quosures are meant to be expression wrappers. This is why you'd use get_expr() to get an actual expression like the one you have represented in this diagram.

I mean to be using it as the root of the AST for an expression, though that isn't clear in my post.

But a quosure is an expression because you can evaluate it just as you can a bare expression, albeit with a different mechanism. Or maybe it's better to say that it's an expression in the language model of R that the rlang package uses.

rlang::is_expr returns TRUE when applied to a quosure and also when applied to the object returned by get_expr. So the rlang package sees quosures as expressions. But rlang is working on a language model of, not the syntax of R. Each has a different idea of what an expression is.

So to me quosure means get me the AST for an expression along with the context of the expression.

The thing I find interesting is that the quosure seems to be a proxy for a lisp list. It, in effect, translates an expression like a * b + c * d, which is a syntax you can use in R but doesn't exist in lisp (or HP RPN calculators for that matter), into a syntax lisp can use, which would be

(+(* a b)(* c d))

That's what the tree I generated and then drew with DiagrammeR is showing.

The first item in a lisp list is returned by rlang::head, and the rest of the list is returned by rlang::tail. These correspond to car and cdr in lisp (I think, sort of) which is a terminology for parts of the architecture of the machines early versions of lisp ran on. Even though I have designed computers I've never, and still don't, understand how car and cdr help explain how lisp works. But as soon as I saw the lang_head and lang_tail functions it all made sense to me.

So mostly what I've been looking at lately is the language model of R which is surfaced by the rlang package.

A quosure is technically an expression but is best viewed as a wrapper or vehicle for expressions, similarly to formulas. No quosure appears in your diagram, it represents a raw expression.

I see what you mean but that is not an expression that I "drew". It was drawn by a function I'm working on that extracts an AST from a quosure.

The model of the R language that rlang uses does not see a literal expression like a + b as an expression, rlang::is _expr produces an error when some like a + b is passed to it. About the only thing is sees as an expression is a quosure or something that is like a quosure.

It's part of the split between the syntax of a language and a module of the languge.

In R when you "program on the language" you don't program on the syntax of it, you program on some model of the language you get from somewhere. In R the model comes from the rlang package. In the model of R a quosure is an expression.

You can program on the syntax of a language but it is hard to do except for simple things. Defines in c are sort of like programming on the c language... that let you insert your own syntax. But defines have a lot more limitations than, for example, programming on the language in R.

html is another example. There is a syntax for html (actually a sgml typedef for it) which doesn't allow any custom tag or attributes. But the W3C DOM (document object model) for web pages which html is translated into in a web page doesn't care about the restrictions put on html by sgml typedef. So in a web page, i.e. javascript, you create and interpret any elements or attributes you want.

Related info from the rlang documentation:

Note that we are using the term expression in its colloquial sense and not to refer to expression() vectors, a data type that wraps expressions in a vector and which isn't used much in modern R code.

(Funnily enough, i use expression() not often but regularly... :disappointed_relieved:)

So we have:

rlang::is_expr(expression(a+b))
# FALSE
base::iis.expression(expression(a+b))
# TRUE

# and cause of eval-order:
base::is.expression(a+b)
# Error: object 'a' not found

I was a big fan of DiagramR as well. One question I have is how you embed the diagram into a file, html or pdf?

If you render in RStudio then you can export it to an image or pdf or put it on the clipboard. From there you can add it to an html page or pdf. If you put the rendering on a clipboard you paste it into a lot of things like messages here in the RStudio community, or a lot of image editors like Photoshop.

There is an export dropdown in the RStudio viewer window when there is an image in it.