3 ms·
It's not, this is that Lisp thing where you can check the length of your argument list and do something completely different when you don't get enough arguments
by crdrost 3y ago
It's not, this is that Lisp thing where you can check the length of your argument list and do something completely different when you don't get enough arguments.
In this case `(map f)` notices that it was told to map a function but not told what to map it over, and so it decides to give you a new function. If this were a partially applied function the signature would be `[x] -> [y]` where `f: x -> y` would pick out the specifics.
But this is actually a totally different signature, isomorphic to `x -> [y]`, the signature of generators. Specifically `(map f)` generates what in Haskell would be `\x -> [f x]`.
However the type is not quite that straightforward for historical and compositional reasons; it is actually
∀z. (y -> z -> z) -> x -> z -> z
With the implementation being here
\handle x -> handle (f x)
This is a sort of enhanced map that can do filtering because it uses concatMap (also known as >>=, “bind in the list monad”) to combine. So to `(filter pred)` you would have the isomorphic versions,
\x -> if pred x then [x] else []
\handle x rest -> if pred x then handle x rest else rest
This also leads to an important nitpick for the article in question, a strictly better mental model of a transducer is not that it maps conveyor belts to conveyor belts, since that has more power than transducers do. (For instance, reverse is not a transducer.) But rather that it maps individual items on a conveyor belt, to their own conveyor belts on the first conveyor belt, then mashes them all together into one effective conveyor belt.
So filter will either map an object to a singleton conveyor belt containing that thing, or an empty conveyor belt. You can implement `dupIf pred x = if pred x then [ x, x] else [x]` as a transducer too, `handle x (handle x rest)`. Conveyor belt that either has one or two elements on it. You can potentially put an infinite conveyor belt inside your conveyor belts and make a chunk of the input unreachable, although Clojure is strict so I have the feeling this will just run out of memory?
- rowbin 3y agoThanks, that helped