lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi] Languages with first-class arrays [Was: Why have all relational op


From: Greg Chicares
Subject: [lmi] Languages with first-class arrays [Was: Why have all relational operators for containers?]
Date: Fri, 26 Mar 2021 00:36:12 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.4.0

On 3/24/21 10:06 PM, Vadim Zeitlin wrote:
> [this is completely OT, please feel free to skip it if you're busy]

'O' can be taken as "On" rather than "Off". I just had my second
shot of Pfizer vaccine, and the only side effect so far is worrying
about side effects, but that worry is a severe side effect that can
only be mitigated by an interesting diversion.

> On Wed, 24 Mar 2021 15:06:04 +0000 Greg Chicares <gchicares@sbcglobal.net> 
> wrote:
> 
> GC> > C++ just doesn't provide vector operations.
> GC> 
> GC> That almost makes me long for 'extern "FORTRAN"'.
> GC> 
> GC> > What you really want is
> GC> > Raku (née Perl 6)
> GC> 
> GC> Well, okay, 'extern "Raku"'.
> 
>  FWIW Raku does provide "extern C++". Or at least C, but as this is done in
> https://github.com/FROGGS/p6-Inline-C by running (transparently, i.e. at
> compilation time) the C compiler, it should be easy to generalize it to C++
> too. This is not one of the features of Raku I really expect to ever use,
> but it's still fun to use a language supporting it.

I once wrote an APL system that called (precompiled) C++ routines.
The C++ code was ten times as fast--it did many of the same things lmi
does, in the same kind of (for year 0..100){(for month 0..11){}} loop,
APL not being the best language for (non-vectorizable) loops. But if Raku
doesn't have such a speed penalty, then calling C++ code from it would
be a less compelling use case.

Anyway, I misspoke. What I want isn't 'extern "FORTRAN"'; it's really
an "APL declaration" parallel to the "asm declaration" [dcl.asm]. Thus:

  // Parallel resistors
  double Rtotal {};
  std::vector<double> R {22.0, 33.0, 47.0, 68.0};
  APL ("Rtotal←÷+/÷R");

  // Equality of two sets
  bool SetsAreEqual {};
  std::vector<int> S {1, 3, 7};
  std::vector<int> T {7, 7, 7, 3, 3, 1};
  APL ("SetsAreEqual←∧/(X∊Y),Y∊X");

(That's how the famous FinnAPL idiom library expresses it. I'd
probably say "(X∧.∊Y)∧Y∧.∊X": there's always more than one way.)

It's not really hard to use C++ to calculate the reciprocal of
a sum of reciprocals, but I could make a mistake while writing
the loop counters. OTOH, "÷+/÷R" is obviously correct: there are
only five characters to consider, so there's little that could
go wrong. You can see the whole algorithm with zero saccades,
which is like operating on registers without having to look
even in an L1 cache.

I imagine you could translate any such example to similar Raku,
with the same advantage that it's easy to validate a terse,
clear expression, and hard to write one that's wrong in some
minor detail (because the minor details are elided).

> GC> [...snip examples...]
> GC> >  Raku operator composability is really very aesthetically pleasant, if
> GC> > nothing else.
> GC> 
> GC> It's much more. With a rich set of operators that are composable,
> GC> we can write code in a terse way the precludes all sorts of errors.
> 
>  Yes. Note that composability in Raku exists in all kinds, i.e. you have
> hyper-operators (4 version of them, as you can use either » or « on either
> direction to indicate whether the shorter list/array should be extended)
> but also
> 
> 1. Can combine any operator with "=", not just "+" or "-", i.e. you could
>    also also write
> 
>       > $x1 max= $x0 # increase $x1 to $x0
>       [4 5 6]

APL doesn't have that. I remember wishing for it in APL after I learned C.

> 2. Reduction meta-operator [...] can be used with any other operator too:
> 
>       > [max] 4,5,6 # to use $x0 you'd have to flatten it: "|$x0"
>       6

Here, as probably in most cases, APL does the same thing, and only
the symbols differ, so it's like translating one Romance language
to another:

  ⌈/4 5 6
6

If $x0 is a 3x1 column vector, you could flatten (we say "ravel")
it with ',':

  X0←3 1⍴ 4 5 6
  ⌈/,X0

or just reduce across rows instead of columns:

  ⌈⌿X0  ['⌿' is shorthand; ⌈/[5]Z reduces across a fifth dimension]

>    It also can return all the intermediate results, which is slightly more
>    useful with max:
> 
>       > [\max] |$x0
>       (4 5 6)
>       > [\max] 6,5,4 # just for illustration
>       (6 6 6)

I suppose they were aware of APL's use of '\' for partial summation,
because in APL we would write:

  ⌈\6 5 4
6 5 4

> 3. Cross and zip metaoperators implement Cartesian and direct product using
>    any operator:
> 
>       > (4,5,6) Xmax (3,9)
>       (4 9 5 9 6 9)

  4 5 6∘.⌈3 9
4 9
5 9
6 9

APL's outer product returns a result whose shape is the concatenation
of the arguments' shapes.

>       > (4,5,6) Zmax (3,9)
>       (4 9)

I guess that's the max-reduction of the max-outer-product above,
which is the max-max inner product:

  4 5 6⌈.⌈3 9
4 9

>    (again, using "max" here is a bit unusual perhaps, but it does work and
>     for all I know this could be a common operation for an APL programmer).

Absolutely. Languages like C may foster a habit of thinking that
+ - * / are somehow special, while exponentiation is not because
it requires a function call; likewise, max, min, etc. Conventional
math notation doesn't help--look at the various ways we write
  2 + 3
  max(2,3)
  log [subscript 2] 3
  2 [superscript] 3
  2 binomial-coefficient 3 [I won't even try to draw that in ASCII]
but add, max, log, pow, and binomial-coefficient are all just simple
two-argument arithmetic functions, and APL gives each a hieroglyph,
written as an infix operator:
  2+3
  2⌈3
  2⍟3
  2⋆3
  2!3
A consistent mathematical notation is a superior tool of thought.

>  Sorry for my exuberance, but this is a part of Raku that I really like
> (spoiler: there are other parts that I like even more!).

You really ought to take a look at APL.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]