I've been held up on the new generalized isotopes due to looking at examples like this one:
attempt: func [
return: [<opt> any-value!]
code [block!]
<local> last'
][
last': the ~
reduce-each ^result' code [
if error? result' [return null]
if @void = result' [continue]
last': result'
]
return unmeta last'
]
Here you see ATTEMPT running a REDUCE-EACH, but asking for the ^META of each expression. Asking for the result in meta form suppresses the automatic promotion of a definitional error (isotopic) to a generic failure. (Re-read the definitional failure post for a refresher.)
The meta of the isotopic error was received as a plain ERROR!. And it handles it by returning null. A void state is handled by continuing--leaving the cumulative result as-is.
(I've explained why the meta state for void is weird. For the sake of argument, let's say it doesn't change under the new rules.)
The BAD! Touch
I've enumerated the reasons why having isotopes generate a ^META which is actually a "BAD! ERROR!" has several advantages. Wrapping up meta in BAD! makes it a better generalized inverse evaluator (UNEVAL) as well as making all the meta states truthy.
But I'm displeased with the impact this has here.
last': the ~
reduce-each ^result' code [
all [
bad? result'
error? unbad result'
] then [
return null
]
if @void = result' [continue]
last': result'
]
return unmeta last'
Obviously the naming is... bad. But I don't like not being able to ask it in a single step, as I could before. It makes it tempting to introduce constructs like BAD-ERROR?
last': the ~
reduce-each ^result' code [
if bad-error? result' [return null]
if @void = result' [continue]
last': result'
]
return unmeta last'
Can We Avoid Making BAD-XXX? or QUOTED-XXX? Tests
One strategy could be if there was some kind of arity-2 BAD test, like:
>> badly? integer! (first [~10~])
== #[true]
This would avoid having to fill the global namespace with a bunch of things like BAD-INTEGER?
You might get the idea that a TYPE OF could encode this, like:
'~integer!~ = type of (first [~10~])
But that's not a BAD! DATATYPE! you're getting on the left. It's a BAD! WORD!, and we don't have any kind of WORD!-to-DATATYPE! equivalence (there are reasons for this, beyond the scope of this thread).
Maybe there's a dialect of containment of some kind (?) like:
match [bad!.integer!] (first [~10~])
Given some recent suggestions, it might be possible to say something like:
if integer? try unbad (first [~10~])
The concept being that if it wasn't wrapped up like ~10~, then you'd get the original value out of the TRY instead of a type error. But then this would be conflated if your original input had been an integer. It would work for the error case since things that aren't bad are quoted, but it doesn't feel good.
It Seems We Should Have a Way Of Asking This...
I look at the ^META code where it doesn't have the bad wrapper on it, and I think "that's so much cleaner". When you multiply it across all the other places that want to process meta arguments, it just feels wrong to throw in all the extra complexity.
Yet it feels like something of a failure that we don't have an easy way of asking if a value is a datatype wrapped in tildes or not. It's a weakness that exists in our ability to ask questions about quoted types as well.
Ultimately, is it the best solution to backpedal on the QUOTE/META unification and accept different tracks?
-
META & UNMETA - promotes isotopes to undecorated form, NULL <=> NULL, promotes non-isotopes to one level quoted higher than they were. Because it can generate blanks and logic false, NULL is not the only falsey result you can receive from a META operation.
-
QUOTE & UNQUOTE - promotes isotopes to their ~bad~ value forms, NULL <=> single apostrophe ('), quotes everything else. Acts as a proxy for "UNEVAL/EVAL" of single values.
Then the question remains about what construct something like FOR-BOTH should use. It wants to act like QUOTE and UNQUOTE except with NULL and VOID passthrough.
Under these rules, it's really a special "don't quote quite everything" version of QUOTE so maybe less is more, and just give it an asterisk... to say "quote but with some kind of twist".
for-both: lambda ['var blk1 blk2 body] [
unquote* all [
quote* for-each (var) blk1 body
quote* for-each (var) blk2 body
]
]
I can't think of what this could be as a refinement. QUOTE/PASSTHRU-NULL-AND-VOID? QUOTE/WITH-HOLES-IN-IT? QUOTE/LEAKY? QUOTE/USUALLY?
Not sure, but I really feel like these should be true by default:
>> quote null
== '
>> quote void
** Error: VOID has no quoted form, use META (or QUOTE* if you want to passthru)
Anyway, this is just the same thing from a week ago running around, and I can't make progress until I pin it down! I'll sleep on it a bit.