APL/D Source Code:

────────────────────────────────────────────────────────────────────────────────

max←{                                   ⍝ Max compiler/interpreter.

    stream←{                            ⍝ Process input stream.
        src rem←''next ⍵                ⍝ next line and remainder.
        ')'=⊃src:envt←retract ⍺         ⍝ quit returning (shy) envt.
        exp←⍺ lambda parse src          ⍝ lambda expr tree from source.
        (⍺ show exp)∇ rem               ⍝ show evaluation of statement.
    }                                   ⍝ {env} ← env :: [src]

    next←{                              ⍝ Next complete expression.
        clean←{(∧\⍵≠'/')/⍵}∘{⍵~' ·'}    ⍝ blanks and comments removed.
        src←clean ⍺ input ⍵             ⍝ clean source line.
        0∊src∊chars:⍺ ∇(⎕←'?')⊢1↓⍵      ⍝ bad char: error and retry.
        ''≡src:⍺ ∇ 1↓⍵                  ⍝ blank lines ignored.
        acc←⍺,src                       ⍝ accumulated source.
        nxt←clean⊃1↓⍵                   ⍝ following line.
        ~'·'∊acc prompt nxt:acc(1↓⍵)    ⍝ complete: srce and remainder.
        acc ∇ 1↓⍵                       ⍝ accumulate current line.
    }                                   ⍝ src [src] ← src :: [src]

    input←{                             ⍝ Input from buffer or keybd.
        ×⍴⍵:{⍞←⍵,⊃⌽⎕TC ⋄ ⍵}⊃⍵           ⍝ next item from buffer, else
        ⍞⊣⍞←⍺ prompt''                  ⍝ prompt and input from keybd.
    }                                   ⍝ src ← src :: [src]

    prompt←{                            ⍝ Prompt string.
        last next←¯1 1↑¨⍺ ⍵             ⍝ joining characters.
        dots←'.'∊last,next              ⍝ trailing or leading dots.
        more←last∊'([,.'                ⍝ more to come.
        depth←0⌈-/+/¨⍺∘∊¨'([' '])'      ⍝ bracket nesting depth.
        dent←0⌈dots+depth-~more         ⍝ indentation for depth.
        cont←4↑(dots∨×depth)/'·'        ⍝ continuation indication.
        cont,∊dent⍴⊂4↑'·'               ⍝ prompt string.
    }                                   ⍝ [char] ← src :: src

    retract←{↑((⊃⍵)∊alph)/↓⍉↑⍵}         ⍝ Envt without primitive defs.

    alph←const'alph'                    ⍝ definition alphabet.

    chars←{                             ⍝ Max alphabet:
        a←alph                          ⍝ names a=z,
        n←'0123456789'                  ⍝ numbers 0-9,
        s←'.()=[,]:+~'                  ⍝ syntax.
        t←'#→',const'vars'              ⍝ type expressions.
        f←⊃↓⍉↑const'ptypes'             ⍝ primitive functions.
        c←⊃↓⍉↑const'cdefs'              ⍝ combinator names.
        l←'\._∇'                        ⍝ lambda syntax.
        ∪a,n,s,t,⍵/f,c,l                ⍝ names, nums, sntx, type, xtra.
    }1                                  ⍝ accept extended Max exprs.

    ⍺←0 4⍴'' ⋄ env←extend↓⍺             ⍝ starting environment.
    script←(⍵≡'')↓↓⎕FMT↑⍵               ⍝ script as vector of vectors.
    env stream script                   ⍝ Input streamed from script.
}

────────────────────────────────────────────────────────────────────────────────

parse←{                                 ⍝ Parse tree from Max source vector.

    prep←''∘{                           ⍝ Preprocess.
        ''≡⍵:⍺                          ⍝ no source: accumulated tokens.
        '\.'≡2↑⍵:⍺ ∇ 2↓⍵                ⍝ \.x      → x
        '\'=⊃⍵:(⍺,⌽2↑⍵)∇'\',2↓⍵         ⍝ \abc.x   → a\b\c\x
        '::'≡2↑⍵:(⍺,'⊤')∇ 2↓⍵           ⍝ ::       → ⊤
        dots←+/∧\⍵='.'                  ⍝ number of 'where' dots.
        ×dots:(⍺,-dots)∇ dots↓⍵         ⍝ . .. ... ··· → ¯1 ¯2 ¯3 ···
        (⍺,⊃⍵)∇ 1↓⍵                     ⍝ accumulate token.
    }

    post←'-' '-' '' ''∘{                ⍝ Postfix from infix.
        st bk ac sk←⍺                   ⍝ StaTe BracKet AcCumulator StacK.
        os←st='⍵'                       ⍝ operand state.
        ''≡⍵:(ac,os↓'?',sk)⍵            ⍝ no source: accumulated tokens.
        s ss←split ⍵                    ⍝ first and remaining source tokens.
        0 1≡os,s∊ops:⍺ ∇'?',⍵           ⍝ missing operand: inject dummy.

        s∊ops:s ∇{                      ⍝ Infix operator:
            '(,'≡bk,⍺:'?'               ⍝ no tuples for the nonce.
            s←('-,'≡bk,⍺)⊃⍺'⋄'          ⍝ cons or statement separator.
            ∆ac ∆sk←ac s,¨s cut sk      ⍝ op slotted into ac-sk stacks.
            '∇'bk ∆ac ∆sk ⍺⍺ ⍵          ⍝ new stacks in '∇' state.
        }ss

        s∊'([':s ∇{                     ⍝ Left paren or bracket.
            sx rm←'-'⍺'' ''⍺⍺ ⍵         ⍝ sub expression and remainder.
            r rr←split rm               ⍝ right bracket and remainder.
            r≠('(['⍳⍺)⊃')]':'?'         ⍝ mismatched brackets: error.
            ∆ac←ac,sx,os/'@'            ⍝ new accumulator.
            '⍵'bk ∆ac sk ⍺⍺ rr          ⍝ output sub expression.
        }ss

        s∊'])':{                        ⍝ Right bracket or paren.
            '∇'=st:'?'                  ⍝ incomplete expression: error.
            ')'=⊃ac,s:'?'               ⍝ (): error.
            ']'=⊃ac,s:'⍬'⍵              ⍝ []: null.
            ')'=s:(ac,sk)⍵              ⍝ sub-expression and remainder.
            (∊ac'⍬,',¨','cut sk)⍵       ⍝ 'a,b]' → a,b,⍬
        }⍵

        ∆ac←ac,(rand s),os/'@'          ⍝ new accumulator.
        '⍵'bk ∆ac sk ∇ ss               ⍝ output operand.
    }

    tree←''∘{                           ⍝ Tree from postfix.
        0=⍴,⍵:⊃⍺                        ⍝ no tokens: accumulated tree.
        t tt←split ⍵                    ⍝ first and remaining tokens.
        ~t∊ops:(⍺,t)∇ tt                ⍝ not an operator: pass it along.
        oo a b←(⊂¯2↓⍺),¯2↑'?',⍺         ⍝ operator:2 operands & remainder.
        t∊',:':(oo,⊂app'⊂'a b)∇ tt      ⍝ cons becomes applied function.
        op←(t∊dots)⊃t'.'                ⍝ restore "where" dot.
        (oo,⊂op a b)∇ tt                ⍝ operator bound with operands.
    }

    split←{(⊃⍵)(1↓⍵)}                   ⍝ First and remaining items.
    cut←{/∘⍵¨1 0=</ops∘⍳¨⍺ ⍵}           ⍝ ⍵ cut at binding strength of ⍺.
    app←{↑{'@'⍺ ⍵}⍨/⌽⍵}                 ⍝ function application.
    rand←{⍵∊⎕D:⎕D⍳⍵ ⋄ ⍵}                ⍝ operand: '0'··'9' → 0··9

    dots←¯1-⍳⍴⎕A                        ⍝ where dots: .a=··.z= → ¯1··¯26
    ⍺←'⋄~⊤,→',dots,'=\:@' ⋄ ops←,⍺      ⍝ Default operator set.
    tree⊃post prep ⍵~' ·'               ⍝ Parse tree from source.
}

────────────────────────────────────────────────────────────────────────────────

const←{                                     ⍝ Implementation constants.

    'alph'≡⍵:'abcdefghijklmnopqrstuvwxyz'   ⍝ Object name alphabet.

    'vars'≡⍵:'⍺⍵∊⍳⍴∆⌽⊖⍉⍙⍷○⍟⍎⍕⍋⍒⍫⍨⊢¥$£¢%⋄'   ⍝ Type variable alphabet.

    'cdefs'≡⍵:⌽{                            ⍝ Combinator definitions:
        ⍵,⊂'I' ' x    ' ' x         '}{     ⍝ I   Smullyan: Identity/Idiot
        ⍵,⊂'K' ' cx   ' ' c         '}{     ⍝ K             Kestrel
        ⍵,⊂'S' ' fgx  ' ' fx(gx)    '}{     ⍝ S             Starling
        ⍵,⊂'B' ' fgx  ' ' f(gx)     '}{     ⍝ B             Bluebird
        ⍵,⊂'C' ' fgx  ' ' fxg       '}{     ⍝ C             Cardinal
        ⍵,⊂'$' ' cfgx ' ' c(fx)(gx) '}{     ⍝ S'            Phoenix
        ⍵,⊂'¢' ' cfgx ' ' c(fx)g    '}{     ⍝ C'            -
        ⍵,⊂'&' ' cfgx ' ' c(f(gx))  '}{     ⍝ B*            Becard
        ⍵,⊂'Y' ' x    ' ' x(Yx)     '}{     ⍝ Y             Sage bird
        ⍵,⊂'∇' ' x    ' ' x(Yx)     '}⍬     ⍝ Y (synonym)

    'ptypes'≡⍵:⌽{                           ⍝ Primitive types:
        ⍵,⊂'+' ' #→#               '}{      ⍝ +  succ
        ⍵,⊂'-' ' #→#               '}{      ⍝ -  pred
        ⍵,⊂'!' ' #→⍺→⍺→⍺           '}{      ⍝ !  nil?
        ⍵,⊂'↑' ' [⍺]→⍺             '}{      ⍝ ↑  head
        ⍵,⊂'↓' ' [⍺]→[⍺]           '}{      ⍝ ↓  tail
        ⍵,⊂'∘' ' [⍺]→⍵→⍵→⍵         '}{      ⍝ ∘  null?
        ⍵,⊂'⊂' ' ⍺→[⍺]→[⍺]         '}{      ⍝ ⊂  cons (link)
        ⍵,⊂'?' ' ⍺                 '}{      ⍝ ?  error
        ⍵,⊂'⍬' ' [⍺]               '}{      ⍝ [] null
        ⍵,⊂'I' ' ⍺→⍺               '}{      ⍝ I  Identitätsfunktion
        ⍵,⊂'K' ' ⍺→⍵→⍺             '}{      ⍝ K  Konstanzfunktion
        ⍵,⊂'S' ' (⍺→∊→⍵)→(⍺→∊)→⍺→⍵ '}{      ⍝ S  VerSchmelzungsfunktion
        ⍵,⊂'Y' ' (⍺→⍺)→⍺           '}⍬      ⍝ Y "Paradoxical combinator"

    'opts'≡⍵:⌽{                             ⍝ Curry/Turner optimisations:
        ⍵,⊂' S(K⍺)(K⍵)  ' ' K(⍺⍵) '}{       ⍝ K
        ⍵,⊂' S(K⍺)I     ' ' ⍺     '}{       ⍝
        ⍵,⊂' S(K⍺)(B⍵∊) ' ' &⍺⍵∊  '}{       ⍝ B*
        ⍵,⊂' S(K⍺)⍵     ' ' B⍺⍵   '}{       ⍝ B
        ⍵,⊂' S(B⍺⍵)(K∊) ' ' ¢⍺⍵∊  '}{       ⍝ C'
        ⍵,⊂' S⍺(K⍵)     ' ' C⍺⍵   '}{       ⍝ C
        ⍵,⊂' S(B⍺⍵)∊    ' ' $⍺⍵∊  '}⍬       ⍝ S'

    'temps'≡⍵:⌽{                            ⍝ Pattern matching templates:
        ⍵,⊂'!' '\_.!_⍵?  '}{                ⍝ if zero.
        ⍵,⊂'+' '\_.!_?⍵  '}{                ⍝ if non-zero.
        ⍵,⊂'-' '⍵(-_)    '}{                ⍝ predecessor.
        ⍵,⊂'∘' '\_.∘_⍵?  '}{                ⍝ if null.
        ⍵,⊂'○' '\_.∘_?⍵  '}{                ⍝ if non-null.
        ⍵,⊂'↓' '⍵(↑_)(↓_)'}⍬                ⍝ split head and tail.
}

────────────────────────────────────────────────────────────────────────────────

compile←{                               ⍝ Combinator expression

    comp←{                              ⍝ Compile expression.
        0=⍴⍴⍵:⍵                         ⍝ C[c] → c
        '@'=⊃⍵:(⊃⍵),∇¨1↓⍵               ⍝ C[e f] → C[e] C[f]
        '\'=⊃⍵:↑abs∘∇/1↓⍵               ⍝ C[\x.e] → Ax[ C[e] ]
    }                                   ⍝ @exp ← :: \exp

    abs←{                               ⍝ Variable abstraction.
        app←{'@'⍺ ⍵}                    ⍝ application node.
        0=⍴⍴⍵:⍺{                        ⍝ atom:
            ⍺=⍵:'I'                     ⍝ Ax[x] → I
            'K'app ⍵                    ⍝ Ax[c] → Kc
        }⍵                              ⍝
        otab opt↑app⍨/⌽'S',⍺ ∇¨1↓⍵      ⍝ Ax[f g] → O[ S Ax[f] Ax[g] ]
    }                                   ⍝ @exp ← :: \exp

    opt←{                               ⍝ Optimise combinator expression.
        0=⍴⍺:⍵                          ⍝ no optimisation.
        fm to tl←(⊃⍺),⊂(1↓⍺)            ⍝ first optimisation and tail.
                                        ⍝
        dict←↓⍉↑fm{                     ⍝ substitution dictionary.
            6=⍴⍺,⍵:↑,/⍺ ∇¨⍵             ⍝ both expressions: recur.
            ⍴⍴⍺:⊂'∘'⍵                   ⍝ atomic ⍵: no match.
            ⍺∊'⍺⍵∊':⊂⍺ ⍵                ⍝ wild card: dictionary entry.
            ⍺≡⍵:'' ⋄ '∘'                ⍝ literal match or mis-match.
        }⍵                              ⍝
                                        ⍝
        '∘'∊⊃dict:tl ∇ ⍵                ⍝ not this opt, try next.
        dict subs to                    ⍝ substitute optimisation.
    }                                   ⍝

    subs←{                              ⍝ Substitute from dictionary.
        tags vals←⍺                     ⍝ split dictionary.
        {                               ⍝
            ⍴⍴⍵:'@',∇¨1↓⍵               ⍝ apply: traverse tree,
            (tags⍳⍵)⊃vals,⍵             ⍝ name: corresponding value.
        }⍵                              ⍝
    }                                   ⍝

    otab←⍺ ⋄ comp ⍵                     ⍝ Compile \exp
}

────────────────────────────────────────────────────────────────────────────────

unify←{                                 ⍝ Unification of type expressions.

    ⍺≡⍵:⍺                               ⍝ Easy if identical.
    isvar←{0≡⊃0⍴⊂⍵}                     ⍝ Type variable test.
    case←isvar¨⍺ ⍵                      ⍝ any type variables?
    1∊case:(case⍳0)⊃⍺ ⍵ ⍺               ⍝ yes: choose the other.

    dist←{                              ⍝ Distinct type variables.
        lv rv←vars¨⍵                    ⍝ left and right expr type vars.
        0=⍴lv∩rv:⍵                      ⍝ already distinct: done.
        to←(1+⌈/lv,rv)+⍳⍴rv             ⍝ vars above those in left expr.
        ↑{⍺ ⍵}∘{rv to xlate ⍵}/⍵        ⍝ left followed by relocated right.
    }                                   ⍝ tex tex ← :: tex tex

    subs←⍬ ⍬∘{                          ⍝ Substitution table.
        ≡/⍵:⍺                           ⍝ early out if identical.
        1 1≡{⊃⍴⍴⍵}¨⍵:↑∇⍨/⌽(⊂⍺),↓⍉↑⍵     ⍝ both exprs deep: traverse each.
        case←isvar¨⍵                    ⍝ which are type vars?
        case≡0 0:(≡/⍵)⊃'?'⍺             ⍝ neither: must match.
        case≡1 1:⍺ merge(</⍵)⌽⍵         ⍝ both: merge into subs table.
        ⍺ merge(~⊃case)⌽⍵               ⍝ either: merge into subs table.
    }                                   ⍝ subs ← subs :: exp exp

    merge←{                             ⍝ Merge new subs into table.
        tag val←⍵                       ⍝ name and value.
        ~tag∊⊃⍺:⍺,∘⊂¨⍵                  ⍝ new name: append subs.
        (⊂val)∊⊃⍺:⍺                     ⍝ avoid cycle.
        cval←⍺ dref tag                 ⍝ current value.
        val≡cval:⍺                      ⍝ early out if no change.
        ↑∇⍨/⌽(⊂⍺),↓⍉↑subs val cval      ⍝ extended subs table.
    }                                   ⍝ subs ← subs :: sub

    fix←{                               ⍝ Fixpoint of function ⍺⍺.
        1∊∊{⍺∊∊⍵}¨/⍵:'?'                ⍝ cycle: error.
        ⍵≡z←⍺⍺ ⍵:⍵                      ⍝ arg ≡ rslt: done.
        ∇ z                             ⍝ arg ≢ rslt: refine.
    }

    refs←{↑⍵{⍺{⍺ ⍵}⍺⍺ xlate ⍵}/⍵}       ⍝ Resolve refs to refs.
    xlate←{⍴⍴⍵:⍺∘∇¨⍵ ⋄ ⍺ dref ⍵}        ⍝ Scalar-wise translation.
    dref←{↑⍵{(⍺⍳⍺⍺)⊃⍵,⊂⍺⍺}/⍺}           ⍝ Dereference from table.
    echk←{'?'∊∊⍵:'?' ⋄ ⍵}               ⍝ Error pervades expression.
    vars←{∪(∊⍵)~⎕AV}                    ⍝ Type variables used in expr.

    stab←refs fix subs dist ⍺ ⍵         ⍝ substitution table.
    echk stab xlate ⍺                   ⍝ left expr xlated from subs table.
}

────────────────────────────────────────────────────────────────────────────────

defn←{                                  ⍝ Extend environment.

    merge←{                             ⍝ Merge current and new \defns.
        ⍺≡⍵:⍺                           ⍝ identical: done.
        1 1≡{⊃⍴⍴⍵}¨⍺ ⍵:⍺ ∇¨⍵            ⍝ both compound: examine each.
        (⍺ ⍵⍳'?')⊃⍵ ⍺ ⍺                 ⍝ one unknown: use the other.
    }

    link←{                              ⍝ Bind external refs from envt ⍺.
        ⍴⍴⍵:(⊃⍵),∇¨1↓⍵                  ⍝ traverse expression scalar-wise.
        ~⍵∊alph:⍵                       ⍝ not a name: preserve.
        (tags⍳⍵)⊃cdefs,⍵                ⍝ replaced with value from envt.
    }

    free←{                              ⍝ Var ⍺ free in exp ⍵?
        0=⍴⍴⍵:⍺=⍵                       ⍝ atom: free if same as var.
        '\'⍺≡2↑⍵:0                      ⍝ var bound here: not free.
        ∨/⍺ ∇¨1↓⍵                       ⍝ not \abs, free in either sub?
    }                                   ⍝ bool ← var :: exp.

    alph←const'alph'                    ⍝ Name alphabet.
    yfree←{⍺ free ⍵:⍺ bindy ⍵ ⋄ ⍵}      ⍝ Bind free var with lambda.
    bindy←{'@' 'Y'('\'⍺ ⍵)}             ⍝ Bind var with lambda.

    tags ldefs cdefs tdefs←⍺            ⍝ Environment.
    _ tag lex←⍵                         ⍝ name and value.
    ~tag∊alph:⍺⊣⎕←'?'                   ⍝ bad name: retain current envt.
    odef←(tags⍳tag)⊃ldefs,⊂lex          ⍝ current \defn.
    ldef←lex merge odef                 ⍝ merged old and new \defns.
    otab←(tags⍳'○')⊃cdefs               ⍝ compilation optimisation table.
    cdef←otab compile tag yfree ldef    ⍝ combinator definition.
    told←(tags⍳tag)⊃tdefs,0             ⍝ existing type defn.
    tdef←told unify ⍺ type cdef         ⍝ new type defn.
    '?'∊∊tdef:⍺⊣⎕←'?'                   ⍝ error: retain existing envt.
    cabs←link cdef                      ⍝ bind external refs @ defn time.
    dnew←tag ldef cabs tdef             ⍝ complete new definition.
    dnew{(⊂⍺),⍵}¨(tag≠tags)∘/¨⍺         ⍝ merged into environment.
}

────────────────────────────────────────────────────────────────────────────────

extend←{                                ⍝ Extend supplied environment.

    ctypes←{                            ⍝ deduce combinator types.
        name args dsrc←⍵                ⍝ template, definition source.
        cdef←parse dsrc                 ⍝ combinator definition.
        temp←args~' '                   ⍝ argument template.
        lexp←↑{'\'⍺ ⍵}/temp,⊂cdef       ⍝ lambda definition.
        mask←(⊃¨⍺)∘{∧/⍵∊⍺}¨orefs        ⍝ mask for safe optimisations.
        cexp←(mask/opts)compile lexp    ⍝ combinator expression.
        tdef←(↓⍉↑⍺)type cexp            ⍝ type definition.
        renv←(name≠⊃¨⍺)/⍺               ⍝ remaining environment.
        renv,⊂name temp cdef tdef       ⍝ environment tuple.
    }                                   ⍝ env ← [src] :: env

    func←{                              ⍝ function table entry.
        name texp←table ⍵               ⍝ name, args and type source.
        temp←(+/'→'=∊texp)⍴'⍵'          ⍝ argument template.
        1 1 0 1\name temp texp          ⍝ function table entry.
    }                                   ⍝ def ← :: [src]

    patn←{{parse ⍵}\⍵}                  ⍝ pattern matching template.
    numb←{⍴⍴⍵:⍺∘∇¨⍵ ⋄ ⍵∊⍺:⍺⍳⍵ ⋄ ⍵}      ⍝ conv ⍺, ⍵, ∊, ··· → 0, 1, 2,
    table←{↑{⍺,⊂vars numb parse ⍵}/⍵}   ⍝ tag with parsed expression.

    vars←const'vars'                    ⍝ type variables.
    cdefs←const'cdefs'                  ⍝ combinator definitions.
    ptypes←const'ptypes'                ⍝ primitive types.
    ctags ptags←⊃¨¨cdefs ptypes         ⍝ combinator and function names.
    opts←'@'parse¨¨const'opts'          ⍝ combinator optimisations.
    orefs←(⊃¨cdefs)∘{⍺∩∊⍵}¨opts         ⍝ optimisation combinator refs.
    temps←↓⍉↑patn¨const'temps'          ⍝ pattern matching templates.

    boot←{1 0 0 1\table ⍵}              ⍝ combinator type bootstrap.
    btab←boot¨(ptags∊ctags)/ptypes      ⍝ bootstrap with primitive types.
    ctab←↑ctypes⍨/(⌽cdefs),⊂btab        ⍝ primitive combinator table.
    ftab←func¨(~ptags∊ctags)/ptypes     ⍝ primitive function table.
    otab←⊂1 0 1 0\'○'opts               ⍝ optimisation table.
    ptab←⊂1 1 0 0\'≡'temps              ⍝ pattern matching templates.
    ↓⍉↑ftab,ctab,otab,ptab,⍵            ⍝ complete environment.
}

────────────────────────────────────────────────────────────────────────────────

equn←{                                  ⍝ Lambda from equation.

    lexpr←{                             ⍝ Lambda expression from equation.
        0=⍴⍴⍺:⍺(env lambda ⍵)           ⍝ simple: finished.
        _ hd tl←⍺                       ⍝ head and tail of fun-arg list.
        hd ∇ tl larg ⍵                  ⍝ traverse subtree to left of '='.
    }

    larg←{                              ⍝ Lambda expr from argt pattern.
        '@'=⊃⍺:⍺ apply ⍵                ⍝ number successor: (+i), (+(+i)),
        0=⊃0⍴⍺:⍺ digit ⍵                ⍝ numeric literal:  0, 1,
        '⍬'=⍺:null ⍵                    ⍝ null list:        [],
        '\'⍺ ⍵                          ⍝ simple name:      i, j,
    }

    apply←{                             ⍝ Apply arg.
        _ fun arg←⍺                     ⍝ fun and arg.
        '+'≡fun:numb pred arg larg ⍵    ⍝ + succ
        '@⊂'≢2↑fun:'?'                  ⍝ not cons: error
        hd←2⊃fun ⋄ tl←arg               ⍝ head and tail.
        list cons hd larg tl larg ⍵     ⍝ list.
    }

    digit←{                             ⍝ Numeric arg.
        ⍺=0:zero ⍵                      ⍝ f 0: ···
        numb pred(⍺-1)∇ ⍵               ⍝ f n:
    }

    subs←{                              ⍝ Substitute ⍵ for '⍵' in ⍺.
        ⍴⍴⍺:⍺ ∇¨⊂⍵                      ⍝ traverse ⍺,
        ⍺='⍵':⍵ ⋄ ⍺                     ⍝ subs '⍵' for ⍵.
    }

    dref←{↑⍵{(⍺⍳⍺⍺)⊃⍵,⊂⍺⍺}/⍺}           ⍝ dereference from table.
    env←⍺ ⋄ temp←(2↑env)dref'≡'         ⍝ pattern matching templates.

    zero←(temp dref'!')∘subs            ⍝ template for zero test.
    numb←(temp dref'+')∘subs            ⍝   ..  ..  .. non-zero test.
    pred←(temp dref'-')∘subs            ⍝   ..  ..  .. predecessor.

    null←(temp dref'∘')∘subs            ⍝ template for null test.
    list←(temp dref'○')∘subs            ⍝   ..  ..  .. non-null test.
    cons←(temp dref'↓')∘subs            ⍝   ..  ..  .. list constructor.

    '=',↑lexpr/1↓⍵                      ⍝ f i j k = ⍵  →  f = \ijk.⍵
}

────────────────────────────────────────────────────────────────────────────────

lambda←{                                ⍝ Lambda expression from parse tree.
    0=⍴⍴⍵:⍵                             ⍝ atom: done.
    op lft rgt←⍵                        ⍝ split expression.
    '='=op:⍺ equn ⍵                     ⍝ equation:
    '.'=op:⍺ local ⍵                    ⍝ local definition:
    op,⍺∘∇¨lft rgt                      ⍝ process subtrees.
}

────────────────────────────────────────────────────────────────────────────────

local←{                                 ⍝ Lambda from 'where' clause(s).

    lexp←{                              ⍝ encapsulate local definitions.
        '='≢⊃⍵:'?'                      ⍝ not both equations: error.
        '='≢⊃⍺:2⊃('=_',⊂⍺)∇ ⍵           ⍝ complete primary definition.
        _ ltag lval←⍺                   ⍝ left equation.
        _ rtag rval←⍵                   ⍝ right equation.
        {'='ltag ⍵}rtag{                ⍝
            0=⍴⍴⍵:(⍺≡⍵)⊃⍵ rval          ⍝ atom:
            case←⍺ free¨1↓⍵             ⍝ name free in subtrees.
            0 0≡case:⍵                  ⍝ neither: omit local defn.
            1 1≡case:'@'('\'⍺ ⍵)rval    ⍝ both: insert lambda abs here.
            op lft rgt←⍵                ⍝ split expr.
            0 1≡case:op lft(⍺ ∇ rgt)    ⍝ pursue right subtree.
            1 0≡case:op(⍺ ∇ lft)rgt     ⍝ pursue left subtree
        }lval                           ⍝ local definition body.
    }                                   ⍝ exp ← exp :: exp

    merge←{                             ⍝ Merge current and new \defns.
        (2↑⍺)≢2↑⊃⍵:(⊂⍺),⍵               ⍝ distinct equation: continue.
        mrg←{                           ⍝ new merged equation.
            1 1≡{⊃⍴⍴⍵}¨⍺ ⍵:⍺ ∇¨⍵        ⍝ both compound: examine each.
            (⍺ ⍵⍳'?')⊃⍵ ⍺ ⍺             ⍝ one unknown: use the other.
        }                               ⍝ merged with previous equation.
        (⊂⍺ mrg⊃⍵),1↓⍵                  ⍝ new head of equations.
    }                                   ⍝ [exp] ← exp :: [exp]

    trav←{                              ⍝ Traverse where clauses.
        op lft rgt←⍵                    ⍝
        lexp←⊂⍺ lambda lft              ⍝
        op≡⊃rgt:lexp,⍺ ∇ rgt            ⍝
        lexp,⊂⍺ lambda rgt              ⍝
    }                                   ⍝ [exp] ← op :: exp

    yify←{                              ⍝ Use Y combinator for recursion.
        eq tag val←⍵                    ⍝ name and equation body.
        ~tag free val:⍵                 ⍝ name not free in body: done.
        abs←'\'tag val                  ⍝ lambda abstraction.
        app←'@' 'Y'abs                  ⍝ applied Y combinator.
        eq tag app                      ⍝ new equation.
    }                                   ⍝ exp ← :: exp

    free←{                              ⍝ Var ⍺ free in exp ⍵?
        0=⍴⍴⍵:⍺≡⍵                       ⍝ atom: free if it's the var.
        '\'⍺≡2↑⍵:0                      ⍝ var bound here: not free.
        ∨/⍺ ∇¨1↓⍵                       ⍝ not \abs, free in either sub?
    }                                   ⍝ bool ← var :: exp.

    defs←¯1↓↑merge/(⍺ trav ⍵),'?'       ⍝ local definitions.
    ↑lexp⍨/⌽(1↑defs),yify¨1↓defs        ⍝ complete definition.
}

────────────────────────────────────────────────────────────────────────────────

type←{                                  ⍝ Type of expression.

    infer←{                             ⍝ Expression type inference.
        0=⍴⍴⍵:⍺{                        ⍝ atom:
            0=⊃0⍴⍵:'#'                  ⍝ number: type num.
            ~⍵∊⊃env:'?'                 ⍝ unbound name: error.
            ⍺ bias env dref ⍵           ⍝ type from environment.
        }⍵                              ⍝ name or literal.
        _ fun arg←⍵                     ⍝ apply node: function and argument.
        op fm to←⍺ ∇ fun                ⍝ function component types.
        op≢'→':'?'                      ⍝ non-function
        base←⍺ next fm to               ⍝ variable base.
        targ←base ∇ arg                 ⍝ right subtree.
        ⊃⌽fm to unify targ 0            ⍝ unified result type.
    }                                   ⍝ tex ← nxt :: exp

    bias←{(⍺ btab ⍵)xlate ⍵}            ⍝ Bias type vars above ⍺.
    btab←{⍺{⍵(⍺+⍳⍴⍵)}vars ⍵}            ⍝ bias table
    xlate←{⍴⍴⍵:⍺∘∇¨⍵ ⋄ ⍺ dref ⍵}        ⍝ Scalar-wise translation.
    dref←{↑⍵{(⍺⍳⍺⍺)⊃⍵,⍺⍺}/⍺}            ⍝ Dereference from table.
    next←{1+⌈/⍺,vars ⍵}                 ⍝ Next avail type variable.
    vars←{∪(∊⍵)~⎕AV}                    ⍝ Type variables used in expr.
    env←1 0 0 1/⍺                       ⍝ type definitions.
    0 bias 1 infer ⍵                    ⍝ normalised inferred type.
}

────────────────────────────────────────────────────────────────────────────────

typex←{                                 ⍝ Type expression.

    query←{                             ⍝ query environment.
        otab←(tags⍳'○')⊃cdefs           ⍝ compile optimisation table.
        obj←otab compile exp            ⍝ object code.
        tex←env type obj                ⍝ expression type.
        tex≡obj:env(rem put'?')         ⍝ error: error.
        env(rem put tfmt tex)           ⍝ display type, return envt.
    }                                   ⍝ env rem ← :: exp

    tfmt←{                              ⍝ Type expr format.
        0=⍴⍴⍵:{                         ⍝ Atom:
            0=⊃0⍴⍵:⍵⊃vars               ⍝ type variable.
            ('⍬'=⍵)⊃⍵'[]'               ⍝ null or constructor.
        }⍵                              ⍝ formatted atom.

        '→'=⊃⍵:∇{                       ⍝ Function type:
            argt rslt←⍺⍺¨⍵              ⍝ arg and rslt types.
            lp rp←('→'=⊃⊃⍵)/¨'()'       ⍝ parens.
            lp,argt,rp,'→',rslt         ⍝ parenthesised expr.
        }1↓⍵                            ⍝ function and argument.

        '@'=⊃⍵:∇{                       ⍝ Cons application type.
            func argt←⍺⍺¨⍵              ⍝ head and tail.
            func≡'⊂':'[',argt           ⍝ leftmost application.
            func,1↓argt                 ⍝ ···:[] → ···]
        }1↓⍵                            ⍝ function and argument.
    }                                   ⍝ tex ← :: exp

    spec←{                              ⍝ Type specification.
        _ tag tex←⍵                     ⍝ name and type expression.
        renv←(tags≠tag)∘/¨env           ⍝ remaining environment.
        told←(tags⍳tag)⊃tdefs,0         ⍝ old type definition.
        tnew←told unify tex             ⍝ new refined type definition.
        '?'∊∊tnew:env(1 put'?')         ⍝ error: error.
        lnew←(tags⍳tag)⊃ldefs,'?'       ⍝ lambda defn or wild card.
        cnew←(tags⍳tag)⊃cdefs,'?'       ⍝ combinator defn or wild card.
        defn←tag lnew cnew tnew         ⍝ new definition.
        xenv←renv,∘⊂¨defn               ⍝ extended environment.
        xenv rem                        ⍝ new envt and remaining cols.
    }                                   ⍝ env rem ← :: def

    put←{rem←⍺⌊⍴,⍵ ⋄ ⍞←rem↑⍵ ⋄ ⍺-rem}   ⍝ Put string to session.

    env rem←⍺                           ⍝ envt and remaining cols.
    tags ldefs cdefs tdefs←env          ⍝ environment.
    op exp tex←⍵                        ⍝ ⊤, exp, type-def.
    vars←const'vars'                    ⍝ type variables.
    tex≡'?':query exp                   ⍝ type query.
    ~(⊂exp)∊const'alph':env(1 put'?')   ⍝ type spec of non-name: error.
    numb←{⍴⍴⍵:⍺∘∇¨⍵ ⋄ ⍵∊⍺:⍺⍳⍵ ⋄ ⍵}      ⍝ conv ⍺, ⍵, ∊, ··· → 0, 1, 2,
    spec vars numb ⍵                    ⍝ type specification.
}

────────────────────────────────────────────────────────────────────────────────

reduce←{                                ⍝ Combinator reduction.

    eval←{                              ⍝ Value of @exp.
        ⍴⍴⍵:(∇ 1⊃⍵)apply 2⊃⍵            ⍝ function application.
        ~⍵∊tags:⍵                       ⍝ number, null or error.
        ⍵'',(tags⍳⍵)⊃defs               ⍝ function suspension.
    }                                   ⍝ exp ← :: exp

    apply←{                             ⍝ Function application.
        '?'≡⍺:'?'                       ⍝ bad function: error.
        0=⍴⍴⍺:(eval ⍺)∇ ⍵               ⍝ evaluate primitive function.
        tag rgs tmp def←⍺               ⍝ name, args, template, defn.
        args←rgs,⊂⍵                     ⍝ extended args vector.
        (⍴args)<⍴tmp:tag args tmp def   ⍝ too few args: suspension.
        tag∊'+-!':tag numb args         ⍝ primitive numeric function.
        tag∊'⊂↑↓∘':tag list args        ⍝ primitive list function.
        eval{                           ⍝ combinator:
            ⍴⍴⍵:'@',∇¨1↓⍵               ⍝ traverse definition,
            (tmp⍳⍵)⊃args,⍵              ⍝ substituting values.
        }def                            ⍝ combinator definition.
    }                                   ⍝ exp ← exp :: exp

    numb←{                              ⍝ Number primitive function.
        n←whnf⊃⍵                        ⍝ strictly numeric first arg.
        '?'=n:'?'                       ⍝ error: error.
        '+'=⍺:n+1                       ⍝ + succ
        '-'=⍺:n-1                       ⍝ - pred
        eval(1+×n)⊃⍵                    ⍝ ! nil?
    }                                   ⍝ exp ← op :: exp

    list←{                              ⍝ List primitive function.
        h←whnf⊃⍵                        ⍝ first arg to weak head.
        '?'≡h:'?'                       ⍝ error: error.
        '⊂'=⍺:↑{'@'⍺ ⍵}⍨/⌽⍺ h,1↓⍵       ⍝ ⊂ cons
        '↑'=⍺:{⍵≡'⍬':'?' ⋄ 1 2⊃⍵}h      ⍝ ↑ head
        '↓'=⍺:{⍵≡'⍬':'?' ⋄ 2⊃⍵}h        ⍝ ↓ tail
        eval(2-h≡'⍬')⊃⍵                 ⍝ ∘ null?
    }                                   ⍝ exp ← op :: exp

    whnf←{                              ⍝ Weak Head Normal Form.
        0=⍴⍴⍵:⍵                         ⍝ atom: done.
        4=⍴⍵:↑{'@'⍺ ⍵}⍨/⌽↑,/2↑⍵         ⍝ function suspension.
        '@⊂'≡2↑1⊃⍵:⍵                    ⍝ list construction: done.
        ∇ eval ⍵                        ⍝ re-evaluate.
    }                                   ⍝ exp ← :: exp

    tags defs←{                         ⍝ Combinator definition table.
        tags temp cdefs tdefs←⍵         ⍝ environment.
        mask←~tags∊'⍬?'                 ⍝ ignoring null and error.
        mask∘/¨tags(↓⍉↑temp cdefs)      ⍝ definition table for eval.
    }⍺                                  ⍝ environment.

    whnf ⍵                              ⍝ Reduce to whnf.
}

────────────────────────────────────────────────────────────────────────────────

show←{                                  ⍝ Display output from statement.

    stmt←{                              ⍝ evaluate each ⋄ segment.
        env rem←⍺                       ⍝ envt and remaining cols.
        '⋄'=⊃⍵:⍺ segs ⍵                 ⍝ separator: evaluate left to right.
        '⊤'=⊃⍵:⍺ typex ⍵                ⍝ type: display or set type.
        '='=⊃⍵:(env defn ⍵)rem          ⍝ definition: extend environment.
        '~'=⊃⍵:⍺ remove ⍵               ⍝ remove: compress environment.
        obj←(env dref'○')compile ⍵      ⍝ object code.
        '?'≡env type obj:⍺ put'?'       ⍝ type error: error.
        ⍺ expr env reduce env link obj  ⍝ show reduced expr.
    }                                   ⍝ env rem ← env rem :: exp

    segs←{                              ⍝ Eval left and right ⋄ segments.
        lft←⍺ stmt 1⊃⍵                  ⍝ envt and cols after left segt.
        sepr←(≢/1⊃¨⍺ lft)/', '          ⍝ separator if output from left.
        (lft put sepr)stmt 2⊃⍵          ⍝ envt and cols after right segt.
    }                                   ⍝ env rem ← env rem :: exp

    expr←{                              ⍝ Session-wide display.
        0=⍴⍴⍵:⍺ put('⍬'=⍵)⊃⌽'[]'(⍕⍵)    ⍝ Atom.
        _ fn arg←⍵                      ⍝ function and argument.
        '@⊂'≡2↑fn:(⍺ put'[')list ⍵      ⍝ list.
        fun←⍺ ∇ fn                      ⍝ envt and cols after function.
        0=⍴⍴arg:fun ∇ arg               ⍝ atomic argument: no parentheses.
        ((fun put'(')∇ arg)put')'       ⍝ show argument in parentheses.
    }                                   ⍝ env rem ← env rem :: exp

    list←{                              ⍝ list items.
        env rem←⍺                       ⍝ envt and remaining cols.
        rem=0:⍺                         ⍝ run off edge of session: quit.
        ⍵≡'?':⍺ put'?'                  ⍝ error: error.
        head←⍺ expr env reduce 1 2⊃⍵    ⍝ envt and cols after head.
        tlex←env reduce 2⊃⍵             ⍝ tail expression.
        tlex≡'⍬':head put']'            ⍝ tail null: end of list.
        (head put',')∇ tlex             ⍝ envt and cols after tail.
    }                                   ⍝ env rem ← env rem :: exp

    remove←{                            ⍝ Removal/retention of names.
        env rem←⍺                       ⍝ envt and remaining cols.
        keep←(⊃env){                    ⍝ names to retain.
            '~'=⊃⍵:⍺~alph∩⍺ ∇ 2⊃⍵       ⍝ remv: exclude name.
            '@'=⊃⍵:∊⍺∘∇¨1↓⍵             ⍝ accumulate names.
            (⍴⍴⍵)↓⊂⍵                    ⍝ atom: name or null.
        }⍵                              ⍝ [char] ← [char] :: exp
        renv←((⊃env)∊keep)∘/¨env        ⍝ reduced environment.
        renv rem put∊2↑¨⌽keep∩alph      ⍝ show remaining definitions.
    }                                   ⍝ env rem ← env rem :: rex

    link←{                              ⍝ Bind external refs from envt.
        ⍴⍴⍵:(⊃⍵),⍺∘∇¨1↓⍵                ⍝ scalar-wise:
        ~⍵∊alph:⍵                       ⍝ not a name: preserve.
        ⍺ dref ⍵                        ⍝ replaced with value from envt.
    }                                   ⍝ exp ← env :: exp

    put←{env rem←⍺ ⋄ env(rem sput ⍵)}   ⍝ Envt and remainder after put.
    sput←{rem←⍺⌊⍴,⍵ ⋄ ⍞←rem↑⍵ ⋄ ⍺-rem}  ⍝ Put string to session.
    dref←{↑⍵{(⍺⍳⍺⍺)⊃⍵,'?'}/1 0 1 0/⍺}   ⍝ Dereference from table.

    alph←const'alph'                    ⍝ definition alphabet.
    maxw←⎕PW-1                          ⍝ maximum output width
    env rem←⍺ maxw stmt ⍵               ⍝ new env and remaining cols.
    ⊃env 1 put(rem<maxw)/⊃⌽⎕TC          ⍝ newline after any output.
}

────────────────────────────────────────────────────────────────────────────────

trees←{                                 ⍝ Format [char;] ← :: exp
    0=≡⍵:⍕⍵                             ⍝ lonely leaf.
    ⍺←'┌─┐' ⋄ ll mm rr←⍺                ⍝ default line drawing chars.
    (0≡⊃0⍴⍵)∨(0≠≡⊃⍵)∨(,3)≢⍴⍵:⍺∘∇¨⍵      ⍝ not a tree: perhaps a spinney?
    1 0↓' '{                            ⍝ dummy header for top node.
        0=≡⍵:↑(⊃1↓⍺)(,⍕⍵)               ⍝ atom - done.
        subs←(' 'll mm)(mm rr' ')∇¨1↓⍵  ⍝ formatted sub trees.
        r c←↑⌈/⍴¨subs                   ⍝ rows and cols.
        fill←r↑⊃⍵                       ⍝ filler between subs.
        mr←{(⍺⍺⌽⊃⍵)(⍺⍺⊃⌽⍵)}             ⍝ mirror operator.
        xsbs←⊢mr{r c↑⍵}mr subs          ⍝ expanded sub trees.
        gap←{+/∧\⍵∊' ',mm}mr xsbs       ⍝ extra space between subtrees.
        cut←⌊/↑+/gap                    ⍝ number of cols to cut.
        rc←cut+lc←-cut⌊⊃gap             ⍝ left cut and right cut.
        lt rt←lc rc{⍺↓¨↓⍵}¨xsbs         ⍝ inside extra cols removed.
        this←{(∨⌿⍵≠' ')/⍵}↑lt,¨fill,¨rt ⍝ outside blank cols removed.
        mask←(⊃⍵)≠⊃↓this                ⍝ left and right spacing.
        repl←{+/∧\⍵}¨(mask)1(⌽mask)     ⍝ replication for header.
        (repl/⍺)⍪this                   ⍝ formatted tree and header.
    }⍵
}

────────────────────────────────────────────────────────────────────────────────


Back to: contents