Skip to content

Hacker’s Corner: Clipboarding APL Arrays

Vector 13:3, page 90

programming techniques implementations

Transcribed from the printed issue; not yet reviewed. Read it in the PDF of the issue, page 90

Motivation

I spent a good few weeks this autumn making sure that the versions of Rain and NewLeaf in Dyalog APL and APL+Win were completely compatible. Pasting blocks of APL code from one to the other (in either direction) is no longer a problem, in fact I have taken to editing code in APL+Win even if the final target is Dyalog — the benefits of code-illumination (so easy to spot accidental globals when they show in yellow) outweigh the minor hassle of a copy+paste.

However, there remained one significant barrier. How do you move an APL array across the great divide? I particularly needed to move NewLeaf page layout definitions, which are deeply nested matrices such as:

      ⎕se.Disp rpt.toc
┌──┬───────────────┬─────────┬─────────┬─────────────────┐
│pg│Table of Con...│200 28   │597 845  │┌──────┬────────┐│
│  │               │         │         ││Orient│Portrait││
│  │               │         │         │└──────┴────────┘│
├──┼───────────────┼─────────┼─────────┼─────────────────┤
│fr│Body           │72 72    │¯144 ¯144│                 │
├──┼───────────────┼─────────┼─────────┼─────────────────┤
│tx│&r             │72 32    │¯144 0   │                 │
├──┼───────────────┼─────────┼─────────┼─────────────────┤
│tx│Table of Con...│198.5 794│¯397 0   │┌────┬───┐       │
│  │               │         │         ││Font│tib│       │
│  │               │         │         │├────┼───┤       │
│  │               │         │         ││Size│24 │       │
│  │               │         │         │└────┴───┘       │
└──┴───────────────┴─────────┴─────────┴─────────────────┘

… so that I could design in either APL and test the layout on the other one. Here is one (very non-technical) solution to the problem.

Solution

For every array, there exists an APL expression which executes to produce it! This expression is a simple character vector, so it should clipboard with no problem at all. When pasted into the ‘other’ interpreter, all you need to do is to press <Enter> to regenerate the original array — simple really.

      xx←'Hello, ''world''' (2 3⍴⍳6)
      lfmt xx
('Hello, ''world''')(2 3⍴1 2 3 4 5 6)
      ⍎lfmt xx
 Hello, 'world'  1 2 3
                 4 5 6
      xx≡⍎lfmt xx
1

Here is what I hacked out, with very little thought as to the design, more or less on a case by case basis:

    ∇ flat←lfmt any;⎕ML
[1]   ⍝ Take any array and flatten it for clipboarding
[2]    ⎕ML←3 ⋄ flat←''
[3]   ⍝ Does it have serious shape at this level?
[4]    :If 1<⍴⍴any
[5]      flat←flat,(⍕⍴any),'⍴'
[6]      any←,any
[7]      :If 0=⍴any
[8]        flat←flat,'⍬'
[9]      :End
[10]   :End
[11]
[12]  ⍝ Do we need to go deeper?
[13]   :If 1<|≡any
[14]     :Select ↑⍴,any
[15]       :Case 0
[16]         flat←flat,'⍬'
[17]       :Case 1
[18]         flat←flat,↑,/'(,⊂',(lfmt↑any),')'
[19]       :Else
[20]         flat←flat,↑,/'(',¨(lfmt¨any),¨')'
[21]     :EndSelect
[22]   :Else
[23]     :If ' '=1↑0⍴any
[24]       any←(1+any='''')/any
[25]       any←'''',any,''''
[26]     :End
[27]     flat←flat,⍕,any
[28]   :End
[29]
[30]  ⍝ Unfortunately () is not valid APL!!
[31]   :If 0=⍴flat
[32]     flat←'⍬'
[33]   :End
    ∇

This still fails to produce exact matches on deeply nested empty things, but I really don’t care enough to bother — perhaps a keen reader would like to give it some rigorous testing and have fun pointing out all the horrid errors!

As a final aside, I recently came across a paper (dated 1976) which proposed control structures very like those used above. I can’t help feeling that if we had had these 20 years ago, APL might still be a mainstream language.