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,⍺/⍵}⍺-⍵}
(muse:
·
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:
·
1↓((1,OFF>ON)PORSCAN 0,ON>OFF)≠(1,OFF≠ON)PNESCAN 0,ON∧OFF
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.
)
Example:
text
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
whistles→→far→→and→wee
text ≡ 4 xtabs ¯4 xtabs text ⍝ full circle
1
{⍵≡4 xtabs ¯4 xtabs ⍵} #.notes.xtabs ⍝ text with embedded linefeeds.
1
See also: Line_vectors getfile
Back to: contents
Back to: Workspaces