Go to the Next or Previous section, the Detailed Contents, or the Amiga E Encyclopedia.


10.6 Unification

In E, unification is a way of doing complicated, conditional assignments. It may also be referred to as pattern matching because that is what it does: it matches patterns and tries to fit values to the variables mentioned in those patterns. The result of a unification is true or false, depending on whether the pattern was successfully matched.

The basic form of a unification expression is:

  expression <=> pattern

The only things that can be used in a pattern are constants and variable names, and lists of patterns. (Strictly speaking, lisp-cells are also allowed, but this variant of unification is beyond the scope of this Guide.) The pattern is matched against the expression as follows:

So, the things in pattern that control whether a match succeeds are the constants and the lists.

If a match succeeds then all variables mentioned in the pattern will be assigned the appropriate values. However, if a match fails you should consider all variables involved in the pattern to have undefined values (so you may need to initialise them to safely use their values again). This is because the actual way that unification is implemented may not follow the rules above in the obvious way, but will have the same effect in the successful case and will affect only the variables mentioned in the pattern if the match fails.

For example, the following program shows a couple of simple unification expressions in use:

PROC main()
  DEF x, lt
  x:=0
  WriteF('x is \d\n', x)
  lt:=[9,-1,7,4]

  /* The next line uses unification */
  IF lt <=> [9,-1,x,4]
    WriteF('First match succeeded\n')
    WriteF('1) x is now \d\n', x)
  ELSE
    WriteF('First match failed\n')
    /* To be safe, reset x */
    x:=0
  ENDIF

  /* The next line uses unification */
  IF lt <=> [1,x,6,4]
    WriteF('Second match succeeded\n')
    WriteF('2) x is now \d\n', x)
  ELSE
    WriteF('Second match failed\n')
    /* To be safe, reset x */
    x:=0
  ENDIF
ENDPROC

The first match will succeed in this example, and there will be a side-effect of assigning seven to x. The second match will not succeed because, for instance, the first element of lt is not one.

We can rewrite the above example without using the unification operator (to show why unification is so useful). This code follows the rules in one particular way, so is not guaranteed to have the same effect as the unification version if any of the matches fail.

PROC main()
  DEF x, lt, match
  x:=0
  WriteF('x is \d\n', x)
  lt:=[9,-1,7,4]

  /* The next lines mimic: lt <=> [9,-1,x,4] */
  match:=FALSE
  IF ListLen(lt)=4
    IF ListItem(lt, 0)=9
      IF ListItem(lt, 1)=-1
        x:=ListItem(lt,2)
        IF ListItem(lt, 3)=4 THEN match:=TRUE
      ENDIF
    ENDIF
  ENDIF
  IF match
    WriteF('First match succeeded\n')
    WriteF('1) x is now \d\n', x)
  ELSE
    WriteF('First match failed\n')
    /* To be safe, reset x */
    x:=0
  ENDIF

  /* The next lines mimic: lt <=> [1,x,6,4] */
  match:=FALSE
  IF ListLen(lt)=4
    IF ListItem(lt, 0)=1
      x:=ListItem(lt, 1)
      IF ListItem(lt, 2)=6
        IF ListItem(lt, 3)=4 THEN match:=TRUE
      ENDIF
    ENDIF
  ENDIF
  IF match
    WriteF('Second match succeeded\n')
    WriteF('2) x is now \d\n', x)
  ELSE
    WriteF('Second match failed\n')
    /* To be safe, reset x */
    x:=0
  ENDIF
ENDPROC

Here's a slightly more complicated example, which shows how you might use patterns made up of nested lists. Remember that if the pattern is a list then the expression to be matched must be a list. If this is not the case (e.g., if the expression represents NIL) then your program could behave strangely or even crash your computer. A similar, but less disastrous, problem is if the converse happens: the pattern is not a list but the expression to be matched is a list. In this case the pointer (to the list) is matched against the pattern constant or assigned to the pattern variable.

PROC main()
  DEF x=10, y=-3, p=NIL:PTR TO LONG, lt, i
  WriteF('x is \d, y is \d\n', x, y)
  lt:=[[23,x],y]

  /* This basically swaps x and y */
  IF lt <=> [[23,y],x]
    WriteF('First match succeeded\n')
    WriteF('1) Now x is \d, y is \d\n', x, y)
  ELSE
    WriteF('First match failed\n')
    /* To be safe, reset x and y */
    x:=10;  y:=-3
  ENDIF

  /* This will make p point to the sub-list of lt */
  IF lt <=> [p,-3]
    WriteF('Second match succeeded\n')
    WriteF('2) p is now $\h (a pointer to a list)\n', p)
    FOR i:=0 TO ListLen(p)-1
      WriteF('   Element \d of the list p is \d\n', i, p[i])
    ENDFOR
  ELSE
    WriteF('First match failed\n')
    /* To be safe, reset p */
    p:=NIL
  ENDIF
ENDPROC


Go to the Next or Previous section, the Detailed Contents, or the Amiga E Encyclopedia.