Look at K and Mathematica (aka Wolfram) for two languages that integrate the ideas from APL and Lisp in a more interesting way. In these languages, multidimensional arrays are represented by nested lists, and all scalar operations are generalized to operate on lists. This is a powerful idea whose benefits go well beyond the linear algebra implemented by LispE.
The idea is most powerful if you have only one kind of list (like in K). So a character string is just a list of characters. A matrix is a list of lists of numbers. Instead of representing bit strings as integers (as LispE does with the bitwise operators), a bit string is a list of booleans. All of your scalar operations (on numbers, booleans, and characters) are generalized to work on lists.
Do you have any good resources for learning K? I have a few bookmarked here but in everything I’ve found there seems to be a lack of practical exercises/projects so I end up forgetting everything I read.
I’m not sure if any of my resources are “good”. Another problem is that there are many dialects of K.
Thanks. The last one is the one I’m trying to follow this time.
K crash course was good. It refers to k7, which is no longer current, though it can still be run via web.
Q for mortals is decent, though very slow.
I believe this is the same as https://github.com/kparc/kcc
Latter is incomplete, in the process of being updated to k9.
Oh, good to know.
LispE operates on tensors, which are implemented as nested lists.
Tensors do not an apl make. Tensors, a concise notation, a rank operator…
In apl, everything is an array, and functions operate homogenously on the same. Power emerges from that.
In lisp, everything is an atom or a pair of things, and functions operate homogenously on the same. Power emerges from that, too.
Newer lisps add things like arrays, but an array is little more than a concession to performance; its role is similar to that of the cons: a container for other objects. Lisp’s language is abstraction, and it speaks it well.
When you try to blend the two, you end up with something that is neither a very good lisp nor a very good apl. (It may be good at being something else. I do not mean to make a value judgement.) Tensors feel more scalar than lisp’s aggregates and more aggregate than lisp’s scalars, and the homogeneity of each language is lost.
Actually, you should have a look on how lists are implemented in LispE (see https://github.com/naver/lispe/blob/master/include/listes.h). They are implemented as arrays, not as lists. I worked with many versions of Lisp over the years, and I had an issue with the idea of pushing elements at the beginning of the list, which is usually quite unnatural in most languages. I opted instead to a different implementation which is composed of two layers: ITEM (the array implementation) and LISTE, which contains a pointer to an ITEM. LISTE also contains an index to the first element in the array. A CDR for instance, creates a LISTE object that shares the same ITEM with the initial list, but move its index one notch over.
I don’t see why something’s being unnatural in one language should have any bearing on that thing’s role in another language.
Which being said, you can push elements to the end of a list, by keeping a pointer to the final cons. Another pattern which is very common is to add elements to the head of a list and reverse it once done.
That’s all mostly beside the point, though; again, the semantic role of arrays in lisp is almost identical to that of conses in this context.
You may be interested in gamelisp for a different take on how to do a “lisp” with a vector rather than cons cells.