Easier Generalized Quoting: <dequote> and <requote>


#1

There are primitives for generalized quoting:

  • quoted? is the test, which is actually a datatype test (the type is QUOTED!)
  • quotes of x counts the number of quote levels
  • unquote x removes one quote level, unquote/depth x count removes more
  • quote x will eventually add quote levels, along with quote/depth

(For today, QUOTE is called UNEVAL. This makes it easier to find places where you've forgotten to switch over to LITERAL or LIT for the old meaning of QUOTE. The weird name actually is what was around to do something similar before generalized quoting... it made a GROUP! with a quote in it, so each step of eval of that group would just remove one level of evaluation.)

So you've got everything you need to work with them. But there are some common scenarios of dealing with them that we can help with.

For instance, sometimes you want to basically see past the quoting level of something and operate on its basic type, then return that thing quoted back to the level you had it. Imagine this:

increment: function [
    return: [<opt> integer!]
    x [quoted! integer!]
][
    num-quotes: quotes of x
    x: dequote x
    if not integer? x [
        fail "Invalid type"
    ]
    if x > 304 [return null]
    return quote/depth (x + 1) num-quotes
]

So this way you get:

 >> increment lit '''303
 '''304

 >> increment lit '''1020
 ; null

It's cool that you can do that, but it's a bit irritating to write. And it's a pattern that happens often.

So here's a tool for helping with that:

foo: function [
    return: [<opt> <requote> integer!]
    x [<dequote> integer!]
][
    if x > 304 [return null]
    return x + 1
]

It has the same behavior, but everything is handled for you automatically, including the type checking. As you can see it doesn't put quote levels back on a null...it assumes null doesn't have the requote rule apply. The exception would be if your input was a quoted null, in which case it would think you meant to support that.

You don't have to use <requote>, you can just dequote a parameter and not add it back in to the result. If you have <dequote> on more than one argument, then the requote will have the sum of the quotes taken off for all arguments. That's a weird heuristic that probably won't come in useful too often, but if it's not what you want you'll have to take a QUOTED! and do your own magic.