[e-lang] Atomic expansion of MatchBindExpr to trinary-define

Kevin Reid kpreid at attglobal.net
Mon May 1 08:09:15 EDT 2006


On May 1, 2006, at 1:46, Mark S. Miller wrote:

> Dean points out that if we give the trinary-define a syntax with a
> left-to-right order that matches its execution order, (e1, e2, p),  
> then we can
> allow it to follow E's normal left-to-right scoping rules without  
> restriction.
> At that point, we should be able to express MatchBindExpr as an  
> expansion to
> trinary-define.
>
> ...For purposes of discussion, we're using the syntax
>
>      e ::= keyword (e1, e2) =~ p

Two issues are being confused here.

/Trinary/-define, while it has its own syntactic issues, already  
exists and works. The new idea is a left-to-right-order definition  
expression, which (other than syntactically) is orthogonal to trinarity.

The =~ expansion below does require trinarity, but not left-to-right- 
order, since (for MatchBindExpr) the kernel-define which contains the  
user's pattern does not also contain the user's specimen expression.

> Given this form of trinary-define, Kevin proposes that, for example,
>
>      left =~ [rA, &rB, [rC]]
>
> should expand to
>
>      def specimen__1 := left
>      keyword(escape ej {
>                  keyword(specimen__1, ej) =~ [rA, &rB, [rC]]
>                  [true, rA, &rB, rC]
>              } catch ex__1 {
>                  def b__1 := Ref.broken(ex__1)
>                  [false, b__1, b__1, b__1]
>              },
>              null) =~ [result__1, rA, &rB, rC]
>      result__1
>
> In this expansion, if 'rA' succeeds but '[rC]' fails, the inner  
> 'rA' stays
> bound and the outer 'rA' is bound to a broken reference. They are  
> explicitly
> different variables, as the semantics of atomic binding demands.

There are only three uses of MatchBindExpr in E-on-CL's expander:

   - MismatchExpr (!~). This is trivial - it expands to  
<MatchBindExpr>.not().
   - MapPattern. This use will go away when 'via' is added.
   - ConditionalExpr (my lousy name for || and &&).

In the interest of readable full-expansions, the third case should be  
expanded directly to kernel-defines.

Our current expansion of e`(def a := b) || (def c := d)` is:

if (def a := b) {
     null =~ [&c]
     __makeList.run(&c, &a)
} else {
     if (def c := d) {
         null =~ [&a]
         __makeList.run(&c, &a)
     } else {
         null
     }
} =~ [&c, &a]

The expansion using LTR defines rather than =~ is:

# (def a := b) || (def c := d)
keyword if (def a := b) {
     keyword __brokenFromBooleanFlow =~ &c
     [true, &c, &a]
} else {
     if (def c := d) {
         keyword __brokenFromBooleanFlow =~ &a
         [true, &c, &a]
     } else {
         __makeBooleanFlowFailure(2)
     }
} =~ [res__1, &c, &a]
res__1

Note that no trinary-defines of either type are involved here.

(The occurrences of __brokenFromBooleanFlow and  
__makeBooleanFlowFailure are where the existing expansion just does  
"null =~ [...]", which gives the irrelevant and confusing result <ref  
broken by problem: <NullPointerException: must be an EList rather  
than null>>.)

-- 
Kevin Reid                            <http://homepage.mac.com/kpreid/>




More information about the e-lang mailing list