Why can this card freeze my REPL?

This very useful answer suggested replacing this code:

(defun describe-paths (location edges) (apply (function append) (mapcar #'describe-path (cdr (assoc location edges))))) 

Wherein:

 (defun describe-paths-mapcan (location edges) (mapcan #'describe-path (cdr (assoc location edges)))) 

I understand conceptually why this should work, but it is not; The second option freezes my REPL, and the CL prompt never returns. I have to restart SLIME. So I looked at it , and I wonder if the fact that mapcan is not using list , but rather nconc , is the reason? Therefore, in reality, these are not identically functioning code blocks?

For the curious, I pass this:

(describe-paths-mapcan 'living-room *edges*)

Where *edges* :

 (defparameter *edges* '((living-room (garden west door) (attic upstairs ladder)) (garden (living-room east door)) (attic (living-room downstairs ladder)))) 

and

 (defun describe-path (edge) `(there is a ,(caddr edge) going ,(cadr edge) from here.)) 
+3
source share
1 answer

I think this is due to describe-edges . It is defined as:

 (defun describe-path (edge) `(there is a ,(caddr edge) going ,(cadr edge) from here.)) 

A quasiquadrat there can be macroexpand .. And you will get:

 (macroexpand '`(there is a ,(caddr edge) going ,(cadr edge) from here.)) ; ==> (CONS 'THERE (CONS 'IS (CONS 'A (CONS (CADDR EDGE) (CONS 'GOING (CONS (CADR EDGE) '(FROM HERE.))))))) 

According to the documentation for mapcan, concatenation is destructive. Looking at the very last whats element returned from describe-path , it exchanges the structure with the next element that it returns, so nconc will do an infinite loop.

If you need to change describe-edges to the following, this will work:

 (defun describe-path (edge) (list 'there 'is 'a (caddr edge) 'going (cadr edge) 'from 'here.)) 
+7
source

Source: https://habr.com/ru/post/1438474/


All Articles