Cons is your friend
kaygun.tumblr.com
kaygun.tumblr.com
With that said, whenever readability is lost for the sake of ego, that is a loss. I'm not accusing the author of that though.
EDIT: Actually you're right, it's all strings on X. I thought the author wanted all lists on X.
This idea is something that Guy Steele has been promoting well before his 2009 ICFP presentation - one of my favorite papers is this one he coauthored with Danny Hillis in 1986: http://cva.stanford.edu/classes/cs99s/papers/hillis-steele-d...
i.e. if you assume that "the list" is implemented with conc (i.e. it's a tree) it's more natural to come up with "the loop" as parallel by default, while starting with a cons list you may more likely end up with a sequential one.
The LCONS is a binary cell which has an associated function. It begins life in a "promised" state. When the CAR or CDR of a LCONS is accessed for the first time, the LCONS is "forced": the function is called, and stuffs values into the CAR and CDR. Then it is dissociated from the LCONS, which behaves like a CONS after that.
In the Lisp dialect built into the TXR tool, I have conses as well as lazy conses. Lazy conses satisfy the consp function, and behave like conses for most intents and purposes.
Lazy conses give you structures that you can feed to functions that expect ordinary conses. Many of those functions instantly become empowered for lazy processing; suddenly they can handle infinite lists.
For some functions, you can easily provide lazy equivalents. A lazy mapcar returns a lazy list, which applies a function to tuples of other lazy lists.
Add the infinite sequences {0, 1, 2, ...} and {10, 11, 12, ...}, then take the first ten elements of the result:
$ txr -p '[[mapcar* + (range 0) (range 10)] 0..10]'
(10 12 14 16 18 20 22 24 26 28)
If you use regular mapcar, it will hang in a loop up trying to construct the whole list as it fills memory. $ txr -p '(list (car "ab") (cdr "ab") (cdr "a"))'
(#\a "b" nil)
Note that the cdr/rest of a one character string isn't the empty string, but nil.So, with a repeating lazy list and a string, we can do the Vigenère cipher in one line:
$ txr -p '[mapcar (ret `@1@2`) "abcd" "1234"]'
("a1" "b2" "c3" "d4")
The mapcar function was modified only very slightly to make this happen correctly for all inputs: its inputs have to be normalized so they are "nil correct": empty vectors and strings have to be mapped to nil. That case does not occur here.Watch what happens with mappend:
$ txr -p '[mappend (ret `@1@2`) "abcd" "1234"]'
"a1b2c3d4"
Now that required a bit of more of a hack inside mappend: mappend looks at the type of the leftmost list operand and notices that it is a string. Therefore it accumulates a string.Wait, mapcar has that hack too!
$ txr -p '[mapcar + "abcd" #(0 1 2 3)]'
"aceg"
It didn't kick in in the first example because the function being mapped did not return characters. It returned strings. Strings are not characters and so they cannot be accumulated to make a string. (But of course they can be appended to make a string, which happened in mappend).I see many people here in the sibling replies appear to have also so thoroughly internalized that "cons is for a list" that they appear to have entirely missed the point of the article.