cvec ← {tabstops←8} ##.xtabs cvec           ⍝ Expand/compress HT chars.

The optional left argument (default 8) defines "tabstop" increments.

For  a  positive  left argument, horizontal tab characters in the right argument
are  replaced  with  appropriate  blanks  and  for a negative left argument, the
reverse happens. Mnemonic:

    +ive -> expand      ⍝ replace tabs with blanks
    -ive -> compress    ⍝ replace blanks with tabs

[xtabs] accommodates linefeed characters in its right argument, so a line-vector
or the content of a whole text file may be converted in one call.

Technical note:

In the coding of the compression case, two subfunctions may be of general inter-
est.  The first, suggested by Morten Kromberg, identifies runs of adjacent 1s in
its boolean vector argument:

    runs ← {s←+\⍵ ⋄ s-⌈\s×~⍵}       ⍝ runs of adjacent 1s.

    runs ← {⍵{⍵-⌈\⍵×~⍺}+\⍵}         ⍝ ditto, but with no local variable.

    runs 0 1 1 1 0 1 0 1 1 0        ⍝ runs of adjacent 1s.
0 1 2 3 0 1 0 1 2 0

and  the  second, by Nicolas Delcros, returns the effect of a state being set ON
by  1s from its boolean left argument, and OFF by 1s from its right argument. In
electronics, this function is known as the "SR (set-reset) flip flop".

    onoff ← {1↓⊃,/∨\¨(1,⍵)⊂0,⍺}     ⍝ on where ⍺=1, off where ⍵=1.

    ons ⋄ offs ⋄ ons onoff offs     ⍝ show ons, offs and resulting state.
0 0 1 1 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 1 0 0 0 1 0
0 0 1 1 1 0 0 0 1 1 1 0 0

Although this does not arise in the coding of xtabs, in general there is a prob-
lem in deciding what to do if ON and OFF bits coincide.  Nicolas gives the foll-
owing alternatives:

    onoff ← {1↓⊃,/∨\¨(1,⍵)⊂1,⍺}     ⍝ priority given to ON, starting ON
    onoff ← {1↓⊃,/∨\¨(1,⍵)⊂0,⍺}     ⍝ priority given to ON, starting OFF
    onoff ← {1↓⊃,/∧\¨(1,⍺)⊂1,~⍵}    ⍝ priority given to OFF, starting ON
    onoff ← {1↓⊃,/∧\¨(1,⍺)⊂0,~⍵}    ⍝ priority given to OFF, starting OFF

and this one,  where coincident ON and OFF signals are ignored, may have pleased
Gérard Langlet. The function starts in state OFF (to start in state ON, we could
just invert the logic: on=0, off=1).

    onoff ← {n←⍺≠⍵ ⋄ ≠\n\2≠/¯1,n/⍺-⍵}

or, with an inner dfn instead of a local variable:

    onoff ← {(⍺≠⍵){≠\⍺\2≠/¯1,⍺/⍵}⍺-⍵}

    There is an intriguing story surrounding the coding of onoff:
    Jim  Weigang says: "In his APL85 paper (on pg. 82), Clark Wiedmann describes
    a  programming  problem  posed  to  STSC  employees. The task was to model a
    state-switching device that toggled state based on signals from two separate
    "on"  and  "off"  wires.  The device can be modeled trivially with a program
    that  loops.  Clark  wrote:  "Over  a period of 10 days, 12 programmers con-
    tributed  14  distinct solutions. Nine of the first ten were incorrect. [The
    correct  one  was  the  looping  version.]  The  eleventh  solution (by Jeff
    Chilton) was the first correct one that was non-iterative. It was:

    The  two  subroutines  [are  partitioned or-scan and notequal-scan, from Bob
    Smith's  APL79  paper]."  Clark  estimated that the "quest for a non-looping
    solution  cost about $13,000 in programming time and correspondence." A year
    or two after this description was published, someone sent Clark a stunningly
    short  solution  that  everyone had missed. One should not underestimate the
    amount  of work it sometimes takes to find noniterative solutions in APL, or
    assume  that  finding  such  solutions  is worth the amount of time spent on
    them. "

    Presumably, the "stunningly short solution" predated nested arrays and part-
    itioned reduction.


whistles        far     and wee

    ht ← ⎕ucs 9                             ⍝ horizontal tab char.

    st ← ht'→'∘subs                         ⍝ show tabs as →.

    st ¯8 xtabs text                        ⍝ compress using 8-tabs
whistles→far→and wee

    st ¯4 xtabs text                        ⍝ compress using 4-tabs

    text ≡ 4 xtabs ¯4 xtabs text            ⍝ full circle
    {⍵≡4 xtabs ¯4 xtabs ⍵} #.notes.xtabs    ⍝ text with embedded linefeeds.

See also: Line_vectors getfile

Back to: contents

Back to: Workspaces