LISP再帰三角形

Oct 30 2020

私の再帰呼び出しは機能していないようです。整数を指定して三角形を作成しようとしています。皆さんの助けを借りて、最終的に同じ行に1行の正しい回数で文字列を印刷することができました。行の印刷の最後に、三角形を呼び出して別の行を1文字短くする再帰呼び出しがあります。なんらかの理由でこの電話に出られないようです。以下のコードを見つけてください、すべての助けを事前に感謝します、それはすべて大いに感謝しています!

注:補足として、returnステートメントのようにLispで関数を停止する方法はありますか?再帰をk = 1で停止し、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(3)

aaa 
aa 
a 

サンプル出力三角形(-3)

aaa 
 aa 
  a

回答

3 adabsurdum Oct 30 2020 at 08:45

まず、それが何をしているのかを正確に決定する必要がありますnewTriangle。呼び出し(print (newTriangle 3))はnewTriangle、が文字列を返す必要があることを示唆します。文字列は、への呼び出しによって出力されますprint。ただし、のOP定義newTriangleは、出力の出力と、三角形の1行を文字列として返すことの両方です。

のnewTriangle値のすべての可能なケースがkこの行に到達する前に使い果たされるため、への再帰呼び出しに到達することはありません。以来kのみがゼロ未満にすることができ、ゼロに等しい、またはゼロよりも大きく、これらの例はすべて再帰呼び出しに到達する前にするためにテストされているので、それは到達しません。また、OPコードのcondステートメントの最後の部分の構文が間違っていることにも注意してください。condブランチの最初の式はテストであり、tここでは、到達した場合に常に評価されるブランチに使用するのが慣例です。しかし、ここではこれほど多くの場合は必要ありません。

newTriangle関数が文字列を返さないはずであるが、副作用として三角形を出力する必要があると仮定すると、それは何をすべきですか?入力番号が0より大きい場合は、入力番号と等しい文字数の行を出力してから、入力を1つ減らして自分自身を呼び出す必要があります。それ以外の場合は何もしません:

(defun print-triangle (k)
  (when (> k 0)
    (princ (make-string k :initial-element #\a))
    (terpri)
    (print-triangle (- k 1))))

この定義はprint-triangle、副作用として三角形を印刷することを強調するために名前が付けられています。ケバブケースはLispで慣用的であり、キャメルケースはそうではないためです。毎回そのノートprint-triangleゼロよりも大きい入力と呼ばれるが、正しい長さの文字列がされて印刷され、その後、改行が(目立た-名前が印刷されているterpriだけで、現在の出力ストリームに改行を書き込む)、呼び出す前にprint-triangle再びk1に減少。

REPLインタラクションのサンプル:

CL-USER> (print-triangle 3)
aaa
aa
a
NIL

代わりに文字列を返すことが目標である場合、1つのアプローチは、結果をパラメーターに保持するヘルパー関数を呼び出すことです。

(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))

ここでnew-triangleは、整数引数を取り、を呼び出してbuild-triangle、整数引数と空の文字列の両方をそのresult位置に渡します。build-triangle関数は、多くのと同じ動作をprint-triangleする前に、代わりにラインを印刷する、それらを用いて連結されているresult改行を含む文字列とともに、。ときにbuild-triangle終了すると、result文字列に戻りますnew-triangle。new-triangleREPLから呼び出すだけで、結果の文字列がデータとして(つまり、引用符で)出力されることに注意してください。printの結果を呼び出すとnew-triangle、文字列がデータとして出力され、文字列が返されます。引用符なしで印刷された文字列を表示するには、formatを使用できます。またはprinc、引用符なしで文字列を出力し、文字列自体を返すを使用することもできます。

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
"