4 ms·
I liked the article, but it was very much "in the weeds". I hack Scheme, and have never written any Haskell, though you have to know some to read the papers. B
by wingo 18y ago
I liked the article, but it was very much "in the weeds".
I hack Scheme, and have never written any Haskell, though you have to know some to read the papers. But when programming in Scheme I find myself wanting monadic operations, like the seed in Oleg's SSAX parsers. But my code that rhymes with monads requires tail recursion, and the author didn't mention tail recursion at all.
I prefer to see monads as fold + tail recursion -- and without the latter, it seems you need the mutation that Common Lisp encourages.
- sctb 18y ago"I prefer to see monads as fold + tail recursion" I don't think this is accurate, monads are orthogonal to both folding and tail recursion. Monads are types representing computation, and providing the operations `bind' and `return'. They're much simpler than many imagine at first. "... and without the latter, it seems you need the mutation that Common Lisp encourages." I agree that when using looping constructs other than recursion, it is often required that a counter or accumulator be mutated. Common Lisp does not encourage _general_ mutation, however, and the standard functions and macros illustrate that.
- jrockway 18y ago> the standard functions and macros illustrate that You do know that nearly all of the standard list functions destroy at least one of their arguments, right? People like to call Lisp a functional language, and you can use it that way, but it is really just a very nice imperative language. Statements like: (loop for x in some-list sum (* 2 x)) are just more efficient in CL than the "functional" approach: (reduce #'+ (mapcar (lambda (x) (* 2 x)) some-list) In this case, the LOOP is about 10x faster than the reduce, probably because it conses about 5000 times less memory. CL is not set up the same way Haskell is, and hence you want to reuse data structures (or never create them) where possible. This is very imperative and very non-functional. (But I am not saying it's bad, LOOP (or ITERATE, which is what I use "in real life") is very easy to read and write.)
- anamax 18y ago> You do know that nearly all of the standard list functions destroy at least one of their arguments, right? Cons, c*r, list, mapc, reduce, the mapping functions (mapcan/mapconc destroys the output of its inputs, but that's different). What definition of "nearly all" are we using?
- Hexstream 18y agoI have a feeling you don't have much CL experience... There really aren't very many CL destructive (mutating) list functions, and I personally almost never use them except on fresh lists (like for example when I nreverse a list I just created with successive pushes) and I'm pretty sure it's standard practice. Let's see what destructive list functions I can find in CL (ref: http://www.lispworks.com/documentation/HyperSpec/Body/c_conses.htm http://www.lispworks.com/documentation/HyperSpec/Body/c_cons...) rplaca, rplacd, nsublis, nsubst*, nconc, nreconc, nbutlast, mapcan, mapcon, nintersection, nset-difference, nset-exclusive-or I took some liberties but that's about 12/58 = 20% destructive functions (push, pop, pushnew are usually used on variables, not list structure). And good style dictates to use them very sparsely... Also, (loop for x in some-list sum (* 2 x)) is pretty functional, you're just mutating x locally but who cares, this is exactly like saying (apply #'+ (mapcar (lambda (x) (* 2 x)))) which is obviously functional.
- Hexstream 18y agoI knew something wasn't quite right. I forgot the sequence functions. So add this to the list: fill, map-into, nreverse, replace, nsubstitute, merge, delete, delete-duplicates So about 20/85 = 23,5%
- jrockway 18y agoPoint conceded. The post I replied to says "CL discourages mutation" which is not true. I said "nearly all sequence functions are destructive", which is also not true. Upon further reflection, I think we can say CL doesn't really care if you mutate or not. There's more than one way to do it :)
- 18y ago
- jrockway 18y ago> I prefer to see monads as fold + tail recursion Are you sure you know what monadic computation is? (I would say, "are you sure you know what monads are", but I don't like to use adjectives as nouns.)
- wingo 18y ago> Are you sure you know what monadic computation is? I think so, but of course I could be wrong. In my ignorance, I understand monadic computation as a functional state transfer in which a seed is threaded through some computation -- be it for purposes of I/O, or in general fold operations. Have you seen the SSAX parser? To my mind, the way that it builds its "answer" by threading seeds through the parse tree is monadic. What do you think?