← Back to context

Comment by gmfawcett

6 years ago

"Everything is difficult in this language" made me smile. :) I mostly agree. There are things things that APL / J make amazingly easy, too, but a lot of simple things are just brutal to me. I'm not a hardcore APL programmer -- I've played with J more than APL, but I'm still a novice at both. I just enjoy the mental challenge sometimes.

To insert items from B into A at point N, you could (in pseudocode, I don't have time to play with APL right now!):

(Take N of A) , B , (Drop N of A)

To remove items from the middle of an array between N and M, I can think of two ways (I might have off-by-one errors here):

- (Take N of A) , (Drop M of A)

- Bools / A

where "Bools" is an array of 1/0 values, and the 1's indicate the elements to keep. As a dyadic verb, "/" means "compress", that is, to keep only the indicated elements from the right-hand object.

I'm sure there are other ways! These are the few ways that my limited brain could come up with. :)

I'm also a novice at APL, despite thousands of lines of session scrollback building up basic lines that almost work then I change one character and INSCRUTABLE ERROR, over and over. Your take,B,drop design looks simple and sensible but the repetition of N is bugging me - I tend towards codegolf more than code clarity. The kind of drop I was hoping to find would be like you can index non-contiguous indices and update them:

    Vector[2 8 5]←100

but instead of them getting value 100, they get deleted.

Or like you can do ~ for set subtraction "without some values" like (⍳9)~5 7 but treating the right argument as indices to remove from the array, rather than values to remove from the array. I feel like there's two patterns which work in the same way as the thing I imagine and a space where the thing I imagine could exist but doesn't. Which I've now tried to code up:

    4 9 8 7 10 11 {(~(⍳⍴⍵)∊⍺)/⍵}'accessibility'
    accssty

It's not so ugly, but that took me down another rabbit hole of why I can't turn that into a train because there seems to be no way to force monadic iota when the trains design wants it to be dyadic. That is I want 3 4(⍳⍴)'accessibility' to come out the same as (⍳⍴)'accessibility' by somehow blocking the iota from having a left arg. Like 3 4(⍬∘⍳⍴)'accessibility' but Dyalog shoves the numbers in as a left arg then complains that the left arg is unavailable. Is this a problem with having to overload every glyph with a double meaning because of limitations on IBM 1960s printer technology, or is this my misunderstanding of tacit code and limited knowledge of operator behaviour, who knows. Maybe in another thousand errors I'll know a little more.

I just enjoy the mental challenge sometimes.

There's no accounting for taste ;)

  • Sorry about the pseudo code but I don’t have an APL font on my phone:

    Vector[(iota rho Vector) set-minus indices to remove]

  • No accounting for taste -- truer words never spoken. :)

    ---

    Abandon all hope, ye who read further.

    I try not to worry too much about making things tacit. But there's a neat trick you can play in J to find a tacit definition for a non-tacit expression (if one can be found). I don't know if there is a counterpart in any common APL distributions.

    First you define an expression in terms of values named 'x' and 'y'. Your goal is to find a tacit verb -- let's say 'T' -- that you can call as 'x T y'. (X is always on the left and y is always on the right, by convention -- compare with ⍺ and ⍵, sort of.) There is a J operation, cryptically named '13 :', which will try to make such an expresssion tacit.

    Here's a quick attempt at writing 'N M drop Y', which will return Y but with the N:M section deleted. Again there might be off-by ones here (you could use Increment/Decrement to fix that):

    Define some 'x' and 'y' values for experimenting:

        x =: 5 10     NB. these will be our N:M indexes
        y =: 'abcdefghijklmnopqrstuv'
    

    Here are examples of Take and Drop (these are just to help you translate between APL and J):

           5 {. y
        abcde
           10 }. y
        klmnopqrstuv
    

    Monadically the same verbs mean First and Last:

           {. x
        5
           }. x
        10
    

    With M and N defined as the first ({.) and last (}.) values of X, take M from Y, and join (,) it up with the result of dropping N from Y:

           (({. x) {. y ) , (}. x) }. y
        abcdeklmnopqrstuv
    

    Close enough! Now here's where we invoke the 'make tacit' verb, '13 :'. We have to wrap the original x/y expression in quotes, to make it a string, and then call it like this:

           13 : '(({. x) {. y ) , (}. x) }. y'
        (] {.~ [: {. [) , ] }.~ [: }. [
    

    There's the magic. The tilde (~) is like ⍨ in APL, and the bare [ and ] represent 'take left value' and 'take right value'. The [: word is called a 'cap' and is used to limit the left side of a verb fork. (Sorry, I don't know the equivalent in APL.)

    And that's our tacit version. We can try it out, give it a name, and try it out again:

           x ( (] {.~ [: {. [) , ] }.~ [: }. [ ) y
        abcdeklmnopqrstuv
           drop =: (] {.~ [: {. [) , ] }.~ [: }. [
           x drop y
        abcdeklmnopqrstuv
           5 10 drop 'abcdefghijklmnopqrstuv'
        abcdeklmnopqrstuv
     

    If you've truly abandoned all hope, the J vocabulary is listed here: https://code.jsoftware.com/wiki/NuVoc

    • Ooh that's interesting, and I can read enough J to see how the basic version works, and a bit of what the tacit version is doing; the left and right functions map to ⊣ and ⊢ in APL, I don't know that the cap [: needs an equivalent because Dyalog APL recognises two functions alone without that, and calls it an "atop" for (fg) is (f(g(x)) or "f atop g".

      But I'm going to have to read more to work out what/how the tacit version works because I have no intuition for telling where the x and y or ⍺ ⍵ enter into them.

      Dyalog have this document for tips for translating d-fns into tacit form: https://dfns.dyalog.com/n_tacit.htm but how that compares to what '13 :' does internally..

      1 reply →