3

I am trying to create an APL function which returns differences (non-identical items with identical index) between two vectors. I have come up with the following and it works fine, subtracting two vectors and discarding zeroes from the result:

func ← {((⍺-⍵)≠0)/(⍺-⍵)}

However, I was not satisfied with repeating the (⍺-⍵) part, so I optimized it a little:

func ← {(⍺ (0≠-) ⍵) / (⍺-⍵)}

That also works ((1 2 3 4) func (4 2 0 4) returns -3 3, as expected), so I went ahead:

func ← {⍺ ((0≠-)/-) ⍵}

And that, in fact, does not work for vectors longer than one element. It just returns 1 whenever there is a difference, without showing how big it is ((1 2 3 4) func (4 2 0 4) now returns 1). Why?

I checked the problematic function both in https://tryapl.org editor and in a local environment - neither works.
I checked the composition rules again - I tried to use the one saying that ⍺ (f g h) ⍵ and (⍺ f ⍵) g (⍺ h ⍵) are equivalent, where in my case:

  • f is the (0≠-) train,
  • g is the compression function /,
  • h is the subtraction funcion -.

Perhaps the most peculiar thing for me - I checked the boxing of two functions. It's identical!

⍝ the working function
⍝ func ← {(⍺ (0≠-) ⍵) / (⍺-⍵)}

    ]boxing on
    ((0≠-))/(-)
┌───────────┬─┐
│┌───────┬─┐│-│
││┌─┬─┬─┐│/││ │
│││0│≠│-││ ││ │
││└─┴─┴─┘│ ││ │
│└───────┴─┘│ │
└───────────┴─┘
⍝ the "broken" function
⍝ func ← {⍺ ((0≠-)/-) ⍵}

    ]boxing on
    ((0≠-)/-)
┌───────────┬─┐
│┌───────┬─┐│-│
││┌─┬─┬─┐│/││ │
│││0│≠│-││ ││ │
││└─┴─┴─┘│ ││ │
│└───────┴─┘│ │
└───────────┴─┘

It's also identical in tree mode and parentheses mode.

What happened? Am I not allowed to nest trains? Did I get my composition parameters wrong? Did I make a typo while checking the boxings?

kamilok04
  • 33
  • 5

1 Answers1

4

I think your problem is that / wants to be an operator in a train. You have to coerce it into its function form:

  1 2 3 4 ((0≠-)⊢⍤/-) 4 2 0 4
┌→───┐
│¯3 3│
└~───┘

The ⊢⍤/ might be weird-looking, but it's the "slash-as-function" pattern to commit to memory when using trains.

Note the difference:

  (0≠-)/-
    ┌┴┐
    / -
  ┌─┘
┌─┼─┐
0 ≠ -

  (0≠-)⊢⍤/-
  ┌────┼─┐
┌─┼─┐  ⍤ -
0 ≠ - ┌┴┐
      ⊢ /
xpqz
  • 3,617
  • 10
  • 16
  • Thank you - this worked like a charm! This structure asks the `/` to take its argument from outside the train rather than grab the thing closest to it (in this case another function), am I thinking correctly? – kamilok04 Mar 11 '23 at 14:21
  • @kamilok04 Well, `⍤/` forces `/` to be a function, since a dyadic operator like `⍤` cannot be to the immediate left of another operator. Everything else follows. – Adám Mar 11 '23 at 19:06