I've been struggling to learn J for a few weeks, and there are several things that make it difficult.
1) Lack of spaces in the majority of code make it difficult to lex let alone parse, meaning I can't tell what the operators are. When people use spaces it makes a difference.
2) Every operator has at least two meanings. Some have three meanings. That's more than 100 operators to memorize and 50 share the same spelling as the other 50.
3) The parsing rules as described strike me as extraordinarily complicated.
The ideas in APL are worth learning. For example striping objects and using grade up to make a concordance or annotate any other data structure. Another example is having the primitives auto-sort collections when searching to get nlogn complexity. Almost any language can use these ideas. If Python is one step up from Standard ML because of dicts and out-of-the-box primitives, then APL is one step up from Python.
If anyone who knows APL well is around, can I ask some simple questions?
1) Do user functions and if statements vectorize? Meaning, if I write a recursive function to implement Euclid's GCD and then pass it two arrays, will it give an array of pairwise GCDs?
gcd(a,b) = if b=0 then a else gcd(b,a mod b)
where = and mod are both vectorized APL primitives.
2) Why do I see so few user functions being used? I would expect application code to consist mostly of specific functions but instead I see line after line of unbroken primitive operators.
In J, user-written verbs have rank _ _ _ (infinite for both unary and binary cases) by default, but you can rerank them with the " operator just like any built-in verb.
Why do I see so few user functions being used? I would expect application code to consist mostly of specific functions but instead I see line after line of unbroken primitive operators.
Lots of purpose-specific functions can be built using composition forms on built-in verbs. The resistance to naming sub-pieces of these compositions is largely a cultural thing but still a point of dispute within the community -- some are very much in favor of giving descriptive names to intermediate results.
I imagine that making user functions would require leaving the one-symbol-one-function spelling system that J programmers are accustomed to, and that spelling system is part of the appeal. Also, if the idiomatic form with primitives is shorter than the name, it's tough to consider the name an improvement. :)
Yeah, some things are so common and small as to not merit their own name except in a tutorial. It might be fun to try using those to construct really garden-pathy code. Stick the fork `+/%#` (average when used on its own) somewhere in a train, but use the dyadic case, or position it so that parsing splits it up.
I found that it quickly becomes a mess with tens of parens when you try to do this. Parsing rules of J are complex and the same sequence of symbols can be parsed in a couple of different ways depending on the context - it's good to keep expressions very short to avoid this.
1) Lack of spaces in the majority of code make it difficult to lex let alone parse, meaning I can't tell what the operators are. When people use spaces it makes a difference.
2) Every operator has at least two meanings. Some have three meanings. That's more than 100 operators to memorize and 50 share the same spelling as the other 50.
3) The parsing rules as described strike me as extraordinarily complicated.
The ideas in APL are worth learning. For example striping objects and using grade up to make a concordance or annotate any other data structure. Another example is having the primitives auto-sort collections when searching to get nlogn complexity. Almost any language can use these ideas. If Python is one step up from Standard ML because of dicts and out-of-the-box primitives, then APL is one step up from Python.
If anyone who knows APL well is around, can I ask some simple questions?
1) Do user functions and if statements vectorize? Meaning, if I write a recursive function to implement Euclid's GCD and then pass it two arrays, will it give an array of pairwise GCDs?
gcd(a,b) = if b=0 then a else gcd(b,a mod b)
where = and mod are both vectorized APL primitives.
2) Why do I see so few user functions being used? I would expect application code to consist mostly of specific functions but instead I see line after line of unbroken primitive operators.
(EDIT: fixed formatting.)