Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement infix:<^^> (in a module) #464

Open
masak opened this issue Feb 9, 2019 · 4 comments
Open

Implement infix:<^^> (in a module) #464

masak opened this issue Feb 9, 2019 · 4 comments

Comments

@masak
Copy link
Owner

masak commented Feb 9, 2019

Can't believe I haven't been missing this one in 007 yet.

We follow Perl 6's semantics for this one, that is, the operator is list associative, short-circuiting, and iff exactly one of its operands is truthy, then it hands back that value. That is, for

a ^^ b ^^ c

The following could happen:

  • All values are falsy. Then it returns c (the last value, which is falsy).
  • Exactly one of a, b, or c is truthy. Then it returns that one.
  • In all the other cases, it returns none (which is a falsy value, but distinct from false). Furthermore, it will not evaluate any argument beyond the second truthy one. (E.g. if a and b are both truthy, c won't be evaluated.)

The last point makes this (ah!) a macro, which is great news. Here's an attempt at an implementation:

macro infix:<^^>(...exprs) is equiv(infix:<||>) is assoc("list") {
    return quasi {
        my n = 0;
        my result = none;
        for exprs -> e {
            my val = {{{e}}};
            if val {
                result = val;  # the "exactly one" case
                n++;
                if n > 1 {
                    result = none;  # the "second truthy one" case
                    last;
                }
            }
            else if result == none {
                result = val;  # the "all values are falsy" case
            }
        }
        result;
    };
}

A small modification involving lvalue() can make it hand back lvalues, too. (Perl 6's does.) But I only feel we need to do that when we can make infix:<||> and infix:<&&> hand back lvalues.

@masak
Copy link
Owner Author

masak commented Feb 9, 2019

I kind of glossed over the fact that in order for this to work, we kind of need a new "list" associativity, too. But yeah, we do.

The other logical infixes are also list-associative, but you can't really tell with them, since the semantics ends up being the same as if they were left-associative. infix:<^^> is different exactly because it needs to keep the n counter (in the code above) across the entire list.

@masak
Copy link
Owner Author

masak commented Mar 21, 2019

This, by the way, is a delightful core module to have early, because it's not waiting on is parsed. Just blocking on modules and imports in general.

@masak
Copy link
Owner Author

masak commented Mar 21, 2019

...and varargs, aka slurpy parameters (#259).

@masak
Copy link
Owner Author

masak commented Jan 11, 2021

...and list associativity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant