The ME and MY Macros: Saving Us From ++ and --

In R3-Alpha, Carl asked the question:

Do We Dare Add ++ and --?

count: 0
++ count  ; add one
-- count  ; sub one

While it's cool that you can do this, I don't like it being in the box. Especially now that double dashes are principally used by strings.

Ren-C Has A Cooler Answer, Using Literal Left Infix

There are two interesting operators called ME and MY.

You put a SET-WORD (or SET-TUPLE) on their left. They take that infix literally. Then they use the value of that as the argument to whatever's on the right.

ME is used when you have an infix function on the right:

>> my-long-variable-name: 0
== 0

>> my-long-variable-name: me + 1
== 1

>> my-long-variable-name
== 1

Whereas MY is used when you have a prefix function on your right, and you want to inject the thing on the left as the first argument to it:

>> my-long-block-name: [a b c]
== [a b c]

>> my-long-block-name: my append [d e]
== [a b c [d e]]

>> my-long-block-name
== [a b c [d e]]

Literate, Generalized, and Easy To Implement

They use the INLINER facility.. (Ideally they would use MACRO, but since MACRO is being written on top of INLINER during its development that would be slower...)

me: infix inliner [
    "Update variable using it as the left hand argument to an infix operator"
    @left [set-word? set-tuple?]
    @right [word! path! chain!]
][
    spread reduce [left, unchain left, right]
]

my: infix inliner [
    "Update variable using it as the first argument to a prefix operator"
    @left [set-word? set-tuple?]
    @right [word! path! chain!]
][
    spread reduce [left, right, unchain left]
]

:smiling_face_with_sunglasses:

1 Like

While this works, it's has a few flaws...

The macro is looking for a SET-WORD! or SET-TUPLE! on the left, and then something indicating the action to run on the right. It replaces the whole sequence with what was on the left, then a plain WORD! or TUPLE! version of what was on the left, and then what's on the right.

This is naive for two reasons:

  • It doesn't check that what the RIGHT parameter looks up to is an action

  • If the SET-TUPLE! in LEFT has a GROUP! in it, then it will be executed twice.

Here is A "Less-Naive" Implementation of ME

me: infix inliner [
    "Update variable using it as the left hand argument to an infix operator"
    @left [set-word? set-tuple?]
    @right [word! path! chain!]
][
    [left ^value]: resolve left  ; avoid double-evaluation
    ensure action! get right
    spread reduce ['set left lift ^value right]
]

The RESOLVE function is used to turn a TUPLE! or PATH! with groups in it into an inert representation:

 >> blk: [a b [c d]]

 >> resolve 'blk.(print "hi", 1 + 2).2
 hi
 == @[blk 3 2]

GET and SET accept these blocks as an alternative to words/tuples to be used to describe what to set or get.

It has to use a BLOCK! representation because not all things can be represented in paths that can be used with picking (note this implies you cannot pick with isotopes, otherwise not all blocks would be resolvable).

So long as RESOLVE is walking the path, you can ask it to give you back the value of what's there.

But For Now, We Use The Naive Form...

Just some notes on how it could be improved, especially if it were made into a native.

3 Likes