⍝ Unification of expressions: ⍝ Here is a parser for simple parenthesised expressions: px←{⎕ml←0 ⍝ Single char token parser. 1=⍴⍵:⊃⍵ ⍝ atom: return scalar. depth←ׯ1⌽-⌿+\'()'∘.=⍵ ⍝ within parens. lpars←0 1⍷depth ⍝ left parens. smask←lpars≥depth ⍝ segmentation mask. drops←1 ¯1×⊂smask/lpars ⍝ parens drop. ∇¨↑↓¨/drops,⊂smask⊂⍵ ⍝ process each segment. } ⍝ and a corresponding de-parser: fx←{ ⍝ Format parse tree. 0=≡⍵:⍕⍵ ⍝ atom: done. ↑,/{ ⍝ join branches. 0=≡⍵:⍵ ⍝ atom: done. '(',⍵,')' ⍝ parenthesise. }∘∇¨⍵ ⍝ each branch. } ⍝ Expressions in x and y: lexp rexp←px¨ '(1×2)+y' 'x+(3×4)' ⍕disp¨ lexp rexp ┌───┬─┬─┐ ┌─┬─┬───┐ │1×2│+│y│ │x│+│3×4│ └───┴─┴─┘ └─┴─┴───┘ ⍝ Unification of expressions: 'xy'unify lexp rexp ┌───┬─┬───┐ │1×2│+│3×4│ └───┴─┴───┘ ⍝ ... formatted. fx 'xy'unify lexp rexp (1×2)+(3×4) ⍝ More complex expressions: xa←' a + (b÷n) - (b × a) + a ' xb←'(1-c) + (c÷2) - d + e ' xc←' f + g - h + (i-3)' vars←lcase ⎕a ⍝ vars: a b ··· z fx vars unify px¨xa xb xc~¨' ' (1-3)+(3÷2)-(3×(1-3))+(1-3) ⍝ Unify can be used to resolve "logical syllogisms", such as: ⍝ ⍝ Socrates is a man; all men are mortal; ergo, Socrates is mortal. s1←'Socrates' 'is' 'man' s2←'Man' 'is' 'mortal' ⍕'man' 'Man'unify s1 s2 Socrates is mortal ⍝ Unify works on any conformable arrays, including those of higher rank. a←2 13⍴2/13↑⎕a b←2 13⍴13↓⎕a a b ┌─────────────┬─────────────┐ │AABBCCDDEEFFG│NOPQRSTUVWXYZ│ │GHHIIJJKKLLMM│NOPQRSTUVWXYZ│ └─────────────┴─────────────┘ ⍝ Variable 'A' propogates through variables A-Z: ⎕a unify a b ⍝ A matches N matches G matches Z matches M ... B. AAAAAAAAAAAAA AAAAAAAAAAAAA ⍝ replace one variable with a constant: (⊃⌽,b)←'*' a b ┌─────────────┬─────────────┐ │AABBCCDDEEFFG│NOPQRSTUVWXYZ│ │GHHIIJJKKLLMM│NOPQRSTUVWXY*│ └─────────────┴─────────────┘ ⍝ Constant '*' propogates through variables A-Z: ⎕a unify a b ⍝ * matches M matches Y matches F matches X ... A. ************* ************* ⍝ Expression unification is used to infer type in some functional languages. ⍝ Here is the BNF for a tiny right-associative type expression: ⍝ ⍝ texp := func | atom ⍝ func := atom→texp | (texp)→texp ⍝ atom := tcon | tvar ⍝ tcon := # ⍝ tvar := ⍺ | ∆ | ∊ | ⍳ | ⍵ ⍝ ⍝ Type variables are ⍺ ∆ ∊ ⍳ ⍵, ⍝ # is the only type constant and ⍝ → is the only type operator. ⍝ Examples of expressions: ⍝ ⍝ #, ⍺, ⍺→⍵, (⍺→∆)→∊→# ⍝ Parser for such expressions: pt←{ ⍝ Parse type expression. ⊃⍬{ ⍝ Parse tree and remainder. 0=⍴⍵:⍺ ⍵ ⍝ done: parse tree and remainder. hd tl←(⊃⍵)(1↓⍵) ⍝ head and tail of expr. '('=hd:↑∇/⍬ ∇ tl ⍝ parenthesised sub-expr: ')'=hd:⍺ tl ⍝ complete sub-expression: '→'=hd:⌽⍺{⍺⍺ hd ⍵}\⌽⍬ ∇ tl ⍝ function: hd ∇ tl ⍝ atom: }⍵~' ' ⍝ ignoring blanks. } ⍝ and a corresponding de-parser: ft←{ ⍝ Format parse tree. 0=≡⍵:⍕⍵ ⍝ atom: done. 0=≡⊃⍵:∊∇¨⍵ ⍝ atomic left branch: no parens. '(',(∇⊃⍵),')',∊∇¨1↓⍵ ⍝ parenthesised left branch. } ⍝ Parse trees for type expressions: pt'⍺→∊→⍳→⍵' ┌─┬─┬─────────┐ │⍺│→│┌─┬─┬───┐│ │ │ ││∊│→│⍳→⍵││ │ │ │└─┴─┴───┘│ └─┴─┴─────────┘ pt'(⍺→∊)→⍳→⍵' ┌───┬─┬───┐ │⍺→∊│→│⍳→⍵│ └───┴─┴───┘ ⍝ Formatted parse tree. Note how redundant parentheses are ignored: ft pt'(⍺→∊)→(⍳→⍵)' (⍺→∊)→⍳→⍵ ⍝ Vars: ⍺ ∆ ∊ ⍳ ⍵ vars←'⍺∆∊⍳⍵' ⍝ Some type expressions: xa←'(⍺→⍺)→∊ ' xb←' ∆→∆ ' xc←' ⍳→(⍵→#)' ⍝ Unified type expressions: ft vars unify pt¨xa xb xc (#→#)→#→# ⍝ The following expressions can't be unified: clash←pt¨ '(⍺→⍺)→⍵' '⍺→(⍵→⍵)' ⍝ However, if the intention is that the variables ⍝ in the expressions be independent, they can be ⍝ distinguished by: dv←{ ⍝ Distinguish Variables ⍺ in exprs ⍵. vlft vrgt←⍺∘∩∘∊¨⍵ ⍝ vars in left and right exprs (vlft∩vrgt){ ⍝ duplicate vars. (⊂⍵)∊⍺⍺:(⍺⍺⍳⊂⍵)⊃⍵⍵ ⍝ var in old: subs new. 0=≡⍵:⍵ ⍝ atom: pass through. ∇¨⍵ ⍝ tree: traverse. }(⍺~vlft)\⍵ ⍝ translated right expr. } ⍝ The left argument of dv is the "pool" of ⍝ variables, available for substitution. ⍕ft¨clash (⍺→⍺)→⍵ ⍺→⍵→⍵ ⍝ Distinguish variables: ⍕ft¨vars dv clash (⍺→⍺)→⍵ ∆→∊→∊ ⍝ Unify succeeds: ft vars unify vars dv clash (⍺→⍺)→∊→∊ ⍝ Errors: ⎕a unify 'ABC' '12' ⍝ length error. 5::Can't unify ⎕a unify 'X' 'X+1' ⍝ occurs check. 11::Can't unify ⍝∇ unify lcase Back to: code Back to: Workspaces