Ruby を使用して DrRacket 関数を作成する

概要

Rubyを使用してDrRacketの追加機能をエミュレートしようとしています。ただし、試してみると、(1 2 3 . 99) ではなく ((1 2 3) . 99) が返されます。既存のリストを使用して追加を正しくエミュレートすることは可能ですか、それとも最初にリストのコピーを作成する必要がありますか?できるだけ早くご返信ください。

解決策

あなたの問題には 2 つのポイントがあります。

append は基本的に cons に似ていますが、基になるリストに項目も追加する必要があるという意味です。ただし、この例では、Pair オブジェクトの状態を変更せずに、実際には文字列を返します。

実際に行う必要があるのは、新しい項目をペア/リスト構造の末尾に追加することです。これを実現するには、(有効なリストであると仮定して) ペアを調べて、最後の項目 (null である必要がある) が見つかるまで調べる必要があります。

 def append(other)
  return false unless list?
  
  if cdr.nil?
    @value2 = other
  else
    cdr.append(other)
  end

  self
end

例のようにインラインに配置する場合は、self を使用して「既存の」オブジェクトを返すことも重要です。

たとえば、次のコードを考えてみましょう。

b = cons(1, Pair.null)
c = cons(4, Pair.null)

puts b.append(c)

ここに追加すると、次の構造が確実に作成されます。

<Pair @value1=1, @value2=<Pair @value1=4, @value2=nil>>

さて、リストを出力するには、さらに別の再帰的問題 (最初のものと同様) が必要です。ペアのリストを確認する必要がありますが、さまざまなケースも考慮する必要があります。そのため、有効なデータ構造を維持することが非常に重要です。

def to_s
  helper_to_s(true)
end

def helper_to_s(started = false)
  str = ""
  str += "(" if started
  str += "(" if started && car.is_a?(Pair)

  if car.is_a?(Pair)
      str += car.helper_to_s
  else
    str += car.to_s
  end

  if cdr.nil?
    str += ")"
  elsif cdr.is_a?(Pair)
    str += " "
    str += cdr.helper_to_s()
  else
    str += " . #{cdr})"
  end

  str
end

いつ ( を開くべきかを再帰呼び出しに伝えることができるように、ヘルパー関数が必要です。さらに、ネストされたペアがすぐに存在する場合も考慮する必要があります。最後に、データ構造のおかげで、cdr がいつオープンされるかを知ることができます) null ではない、つまり純粋なリストではないことを意味します。この場合、 . を最後の文字列に連結するだけで、 to_s 呼び出しで適切に表示されます。

さらに質問がある場合は、ラケットのドキュメントのペアとリストのドキュメントを必ず確認してください: https://docs.racket-lang.org/guide/Pairs__Lists__and_Racket_Syntax.html これは非常に役立ちます。