Easier Generalized Quoting: <dequote> and <requote>

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

 >> 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.

1 Like

The <dequote> and <requote> parameter flags definitely represent a useful intention.

If the INTEGER! example I give doesn't compel you, let's say you want to SKIP around in a series while it's quoted, and item is ''[a b c].

Would you rather write:

num-quotes: quotes of item
item: quote/depth (skip (dequote item) 2) num-quotes)

...or something like:

item: skip item 2 

Note: remember you could also use the MY operator, with item: my skip 2

Useful Though It Is, It's Currently Too Built-In

There's bits and tweaks in the evaluator for this feature, that probably shouldn't be there. As a technical matter, <dequote> and <requote> are consuming two typecode slots, and I'd like to have those back to try implementing things like COMMA!.

I'm thinking that we need a REQUOTE tool that would be able to take care of it.

So again, if item is ''[a b c]:

>> requote skip item 2
== ''[c]

I've posted about some of the mechanical implications of REQUOTE being a function that invasively takes over the evaluation process. And I mention changes that would help us not lose composability, e.g. so you could instead write:

>> item: my requote skip 2
== ''[c]

I won't rehash that post here. But I do have an observation...

QUOTE! Can Be Seen As a Monad...Do We Care?

When you think about doing an operation on something "inside" a quote "container"...it looks an awful lot like monads...

REQUOTE might be better expressed in terms of some general transformation framework for mapping, and that mapping language might be where to look next.

But for now, killing off <dequote> and <requote> is a step forward. Not much was using it, and it was contaminating the specification of functions that are more cleanly defined without it. This lets callers be more purposeful about when they mean quoted things to be OK, and I feel that helps avoid an aspect of randomness and "dirt" of incidental quotes that are permitted to be left on when they shouldn't be.