one of many possible solutions:
{(1○⍺)>2○⍵} {(⍹ ⍵)/⍨⍵ ⍶ ⍹ ⍵} {⍵*2} {⍵/⍨2|⍵}⍳50
1 9 49 225 361 441 625 1089 1521 1681 2025 220919 karma · joined May 3, 2020
one of many possible solutions:
{(1○⍺)>2○⍵} {(⍹ ⍵)/⍨⍵ ⍶ ⍹ ⍵} {⍵*2} {⍵/⍨2|⍵}⍳50
1 9 49 225 361 441 625 1089 1521 1681 2025 2209 {⍵/⍨⍵<50}{2*⍨⍵/⍨1=2|⍵}⍳10
1 9 25 49
About as short as I can make it, and while its longer than the pandas solution, the primitives are significantly more general (sqr, odd - why include these as language primitives?).I'm of the opinion that code should be documented. Short description, arguments, return, purpose etc. However rebinding primitives kindve defeats the purpose after a little familiarity. For example:
commute ← {⍵ ⍶ ⍺} ⍝ or commute ← { ⍺ ⍶⍨ ⍵ }
will get tedious quickly. Its better to lean into the terseness of the language, rather than attempt to transform it into something it isn't. There has been work done for easing the learning curve, for example https://aplcart.info/ . Keep in mind aplcart generally targets dyalog, however many of the idioms should work for alternate implementations with possibly some tweaking.
APL has an initially steep learning curve, because it is so distinct historically from other languages. But it is a quite simple language once you learn it.
1. Every statement is executed right-to-left. Statements are executed top to bottom (or left to right with ◊ as a separator).
2. The only precedence rule is parentheses
3. Functions can be called with one operand (monadic) or two (dyadic)
4. Values in APL have a shape (dimensional size), a rank (number of dimensions), and a ravel (a list of elements). Values can contain other values (nesting)
{} define lambdas
⍺ is the left operand
⍵ is the right operand
⍶/⍹ are the left/right operators (higher-order functions)
← assignment
◊ statement separators
¨/\⌿⍀⍣⍤⍨ builtin higher order functions
After some familiarity it becomes as easy (or easier) to read as any other language. You can encode a remarkable conciseness of expression into each lambda, that you plumb together (similar to unix pipes in a way) in higher order patterns.For specific points, I would love to see an APL dialect that adopts parts of J, K & haskell. Something that retains the symbolic notation, that provides a deeper & more fluid interface to asm/C, adds some ALGOL-like control-flow constructs, and takes advantage of the intervening decades of programming theory.
APL to me is an alternate history of what programming could have been. Its not perfect by any means, but it boldly challenges assumptions about what it means to communicate mathematical thought. It was ahead of its time, and its unfortunate its taken this long for languages to superficially adopt its insights.
PS: gnu apl is a great FOSS implementation that is enjoyable to use and rich in features.
slightly verbose example but heres gnu apl as a pipe-like interface. Often this would be abstracted to a library that gets included when you call it:
printf "1,2,3,4\n5,6,7,8" | apl --eval "f←{4⎕CR ⍵}◊s←{⍺~⍨¨⍵⊂⍨1++\⍺⋸⍵}◊f ⊃{⍎⎕UCS ⍵}¨¨44 s¨10 s⊣⎕FIO[41] 0"
┏→━━━━━━┓
↓1 2 3 4┃
┃5 6 7 8┃
┗━━━━━━━┛
DESCRIPTION: --eval ≡ evaluate the text
f ≡ formatting function for printing nested values
s ≡ partition a line of text and remove the partition character
⎕FIO ≡ read stdin as byte stream (see FILE_IO.apl)
⎕UCS ≡ convert bytes to characters
⍎ ≡ execute an expression (convert characters to numbers)
SUMMARY: read stdin as a bytestream
partition at newlines and commas
convert to characters
interpret characters as numbers
disclose into a rank-2 array
format to stdout