使用Ruby制作DrRacket `append`函数

问题描述 投票:0回答:1

我正在尝试使用 Ruby 来模拟 DrRacket 中的

append
函数。然而,当我尝试时,我得到的是
((1 2 3) . 99)
而不是
(1 2 3 . 99)
。我相信这与我的
to_s
方法有关,因此我尝试在附加新值之前先创建列表的新副本。但我不知道该怎么办。请尽快指教。

#Project 4
#Kevin Iwatsuki
#Description: This program is meant to help the user become familiar with the basics of Ruby by duplicating the Racket programming language's pairing mechanisms (cons, car, cdr, etc.). 
##########
#Pair (class): Takes two values and creates a pair from them in the style of the Racket programming language. Executing the code should return a pair or list without displaying any output.
#   Returns: A pair or list.
#   Parameters:
#       value1 (any class, including pair) - a value to insert into list.
#       value2 (any class, including pair) - another value to insert into list.
#
#Declare class `Pair`
class Pair
    #initialize: Constructor that enables the creation of Pair objects. This one declares that the objects must have two parameters.
    #   Returns: A new Pair class object.
    #   Parameters:
    #       value1 (any class, including pair) - a value to insert into list.
    #       value2 (any class, including pair) - another value to insert into list.
    def initialize(value1, value2)
        @value1 = value1
        @value2 = value2
    end

    #car: return the first value of the pair.
    #   Returns: The first value of a pair.
    #   Parameters: none
    def car
        return @value1
    end
    
    #cdr: return the values after the first value of the pair.
    #   Returns: The the values after the first value of the pair.
    #   Parameters: none
    def cdr
        return @value2
    end
    
    #to_s: Uses helper_to_s to return a string representation of the pair or list.
    #   Returns: A string of the pair/list.
    #   Parameters: none
    def to_s
        return "(#{helper_to_s}" 
    end

    #helper_to_s: A method that uses recursion to return the appropriate string objects for the pair/list. Meant to be used by the `to_s` method.
    #   Returns: A string of the pair/list to be used with to_s.
    #   Parameters: none
    def helper_to_s
        #Base case: If value1 and value2 are not Pair class objects and value2 is not a nil value, then return a string representing a pair.
        if(@value1.class != Pair && @value2.class != Pair && @value2 != nil)
            return "#{@value1} . #{@value2})"
        #Recursive Case: If value1 is a Pair object and value2 is not a Pair and also not a nil value, submit value1 to `helper_to_s`` for recursion and print the results as a string along with the cdr. The returned value will be in pair form.
        elsif(@value1.class == Pair && @value2.class != Pair && @value2 != nil)
            return "(#{car.helper_to_s} . #{cdr})"
        #Base case: If value2 is a nil value, then return a string representing a list.
        elsif(@value2 == nil)
            return "#{@value1})"
        #Recursive case: If the second value is a Pair object, recursively call the helper function using the cdr until a base case is reached.
        elsif(@value2.class == Pair)
            return "#{@value1} #{cdr.helper_to_s}"
        end
    end 

    #list?: One of two list? methods. Checks if a pair/cons is a list.
    #   Returns: true if pair is a valid list and false otherwise.
    #   Parameters: none
    def list?
        #If value2 is a pair...
        if (@value2.class == Pair)
            #...Recursively call the list? method again with the cdr method.
            cdr.list? #Recursion
        else
            #If value2 is a null (nil) value, then it is a list.
            if (@value2 == nil)
                return true
            else
                return false
            end
        end
    end

    #Method: append(other) - If the pair is a list, append should return a new list consisting of `other`` appended to the original list. 
    def append(other)
        #First, we must check if the Pair object to append to is a list. 
        if(!list?)
            # Return false if not a list.
            return false
        #If Pair object to append to is a list, do the following:
        else 
            return "(#{helper_append(self)} . #{other})"
        end
    end

    #Helper method for append method.
    def helper_append(lst)
        return lst.car
    end

    #self.null: Define a null method in Pair class so `Pair.null` can be used.
    #   Returns: nil value
    #   Parameters: none
    def self.null
        nil
    end

end

#Opens Ruby's NilClass for the sake of adding methods applicable for null values.
class NilClass
    #list?: One of two list? methods. When checking if a `Pair.null` is a list, we must create a `list?` method for the preexisting NilClass in Ruby.
    #   Returns: true if only `Pair.null`` is being checked.
    #   Parameters: none
    def list?
        #A null list is always a list.
        return true
    end

    #Return an empty list if a Pair.null is found.
    def to_s
        return "()"
    end
end

#cons: A global method that creates a new Pair class object whenever invoked.
#   Returns: A new Pair object.
#   Parameters:
#       val1 (any type, including pair) - a value to insert into cons.
#       val2 (any type, including pair) - another value to insert into cons.
def cons(val1, val2)
    Pair.new(val1, val2)
end

#1.)
a = Pair.new(5, 7)
puts a.append(99) #should return false

# #2.)
b = cons(1, cons(2, cons(3, Pair.null)))
puts b.append(99) #Should return (1 2 3 . 99)
ruby
1个回答
0
投票

您的问题有两点:

  1. 数据结构

append
基本上类似于
cons
,从某种意义上说,它还应该向底层 list 添加项目。然而在这个例子中,它实际上返回一个字符串,而不改变
Pair
对象的状态。

您实际需要做的是将

append
新项目添加到
pair/list
结构的末尾。为了实现这一点,您需要遍历这些对(假设它是一个有效的列表),直到找到最后一项,它应该是
null

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

  self
end

如果您想要

self
内联(如您的示例中所示),则使用
puts
返回“现有”对象也很重要。

以下面的代码为例:

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

puts b.append(c)

append
这里将确保创建以下结构:

<Pair @value1=1, @value2=<Pair @value1=4, @value2=nil>>
  1. 打印
    list

现在,为了打印列表,这又是一个递归问题(就像第一个问题一样)。您需要浏览配对列表,但也要考虑不同的情况。这就是为什么保持有效的数据结构如此重要。

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

我们需要一个

helper function
,以便我们可以告诉递归调用何时
open
(
。此外,我们还需要立即考虑嵌套对的情况。最后,由于我们的数据结构,我们可以判断 cdr 何时不是
null
,这意味着它不是
pure list
,在这种情况下,我们可以简单地将
.
连接到最终字符串,它将在
to_s
致电。

如果您还有其他问题,请务必查看球拍文档中的配对和列表文档:https://docs.racket-lang.org/guide/Pairs__Lists__and_Racket_Syntax.html这真的很有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.