Triangle récursif LISP
Mon appel récursif semble ne pas fonctionner, j'essaie de créer un triangle avec un entier, et avec l'aide de vous, j'ai finalement pu imprimer la chaîne sur la même ligne, le nombre correct de fois pour 1 ligne. A la fin de l'impression de la ligne, j'ai un appel récursif qui appelle le triangle pour faire une autre ligne, un caractère plus court. Cet appel semble ne jamais être atteint pour une raison quelconque. Veuillez trouver le code ci-dessous, merci à tous d'avance pour toute aide, tout cela est grandement apprécié!
Remarque: Sur une note latérale, existe-t-il un moyen d'arrêter une fonction en Lisp similaire à une instruction return? Je voudrais que la récursion s'arrête à k = 1 et ne continue pas à k = 0.
(defun newTriangle (k)
(cond ((<= k 0) (princ '(Nope)))
((or (= k 1) (= k -1)) (princ 'a))
((> k 0) (make-string k :initial-element #\a))
(newTriangle (- k 1))))
(print (newTriangle 3))
triangle de sortie d'échantillon (3)
aaa
aa
a
triangle de sortie d'échantillon (-3)
aaa
aa
a
Réponses
Tout d'abord, vous devez décider exactement de ce que cela newTrianglefait. L'appel (print (newTriangle 3))suggère que newTriangledevrait renvoyer une chaîne , qui est ensuite imprimée par l'appel à print. Mais, la définition OP de newTriangleest à la fois l'impression de la sortie et le renvoi d'une seule ligne du triangle sous forme de chaîne.
L'appel récursif à newTrianglen'est jamais atteint car tous les cas possibles pour la valeur de ksont épuisés avant que cette ligne ne soit atteinte. Puisque kne peut être que inférieur à zéro, égal à zéro ou supérieur à zéro, et puisque tous ces cas sont testés avant d'atteindre l'appel récursif, il n'est jamais atteint. Notez également que le code OP a une syntaxe incorrecte pour la dernière partie de l' condinstruction. La première expression d'une condbranche est un test, et la convention est à utiliser tici pour une branche qui sera toujours évaluée si elle est atteinte. Mais, ces nombreux cas ne sont pas nécessaires ici.
En supposant que la newTrianglefonction ne doit pas renvoyer une chaîne, mais doit afficher un triangle comme effet secondaire , que doit-elle faire? Si le nombre d'entrée est supérieur à 0, il doit imprimer une ligne avec un nombre de caractères égal au nombre d'entrée, puis s'appeler avec l'entrée réduite de un; sinon il ne devrait rien faire:
(defun print-triangle (k)
(when (> k 0)
(princ (make-string k :initial-element #\a))
(terpri)
(print-triangle (- k 1))))
Cette définition est nommée print-trianglepour souligner qu'elle imprime un triangle comme effet secondaire, et parce que kebab-case est idiomatique en Lisps, et camelCase ne l'est pas. Notez que chaque fois que cela print-triangleest appelé avec une entrée supérieure à zéro, une chaîne de la longueur correcte est imprimée , puis une nouvelle ligne est imprimée (avec le nom obscur terpri, qui écrit simplement une nouvelle ligne dans le flux de sortie actuel), avant d'appeler à print-trianglenouveau avec kréduit de 1.
Exemple d'interaction REPL:
CL-USER> (print-triangle 3)
aaa
aa
a
NIL
Si l'objectif est plutôt de renvoyer une chaîne, une approche serait d'appeler une fonction d'assistance qui conserve le résultat dans un paramètre:
(defun new-triangle (k)
(build-triangle k ""))
(defun build-triangle (k result)
(if (> k 0)
(build-triangle (- k 1)
(concatenate 'string
result
(make-string k :initial-element #\a)
(string #\newline)))
result))
Ici, new-triangleprend un argument entier et appelle build-triangle, en passant à la fois l'argument entier et une chaîne vide dans la resultposition. La build-trianglefonction fonctionne à peu près de la même manière que print-triangleprécédemment, mais au lieu d'imprimer les lignes, elles sont concaténées avec result, avec une chaîne contenant une nouvelle ligne. Une fois build-triangleterminé, la resultchaîne est renvoyée à new-triangle. Notez que le simple appel new-triangledepuis le REPL affichera la chaîne résultante sous forme de données (c'est-à-dire avec des guillemets); appeler printle résultat de new-triangleaffichera à la fois la chaîne sous forme de données et retournera la chaîne. Pour voir la chaîne imprimée sans guillemets, formatpeut être utilisé; ou vous pouvez utiliser princqui imprimera la chaîne sans guillemets et retournera la chaîne elle-même:
CL-USER> (new-triangle 3)
"aaa
aa
a
"
CL-USER> (print (new-triangle 3))
"aaa
aa
a
"
"aaa
aa
a
"
CL-USER> (format t "~A" (new-triangle 3))
aaa
aa
a
NIL
CL-USER> (princ (new-triangle 3))
aaa
aa
a
"aaa
aa
a
"