I am trying to use Ruby to emulate an append
function from DrRacket. However, when I try it, I get ((1 2 3) . 99)
instead of (1 2 3 . 99)
. Is it possible to correctly emulated append
with a preexisting list, or do I need to make a copy of it first? Please reply at your earliest convenience.
There are two points to your problem:
append
is basically like cons
, in the sense of it should also add items to the underlying list. However in this example, it actually returns a string, without altering the state of the Pair
object.
What you actually need to do, is to append
the new item to the end of the pair/list
structure. To achieve this you need to walk through the pairs (assuming it is a valid list) until you find the last item, which should be null
.
def append(other)
return false unless list?
if cdr.nil?
@value2 = other
else
cdr.append(other)
end
self
end
It is also important that you return the "existing" object with self
if you want to puts
inline, like in your example.
Take for example the following code:
b = cons(1, Pair.null)
c = cons(4, Pair.null)
puts b.append(c)
append
here will make sure that the following structure is created:
<Pair @value1=1, @value2=<Pair @value1=4, @value2=nil>>
list
Now, in order to print the list it is yet another recursive problem (like the first one). You need to walk through the list of pairs but also account for the the different cases. That's why keeping a valid data structure in place is so important.
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
We need a helper function
so that we can tell the recursion call when to open
the (
. Additionally we also need to account for the case when we have nested pair right away. Finally, thanks to our data structure we can tell when the cdr is not null
, meaning it's not a pure list
, in this case we can simply concatenate a .
to the final string and it will show it properly in the to_s
call.
If you have further questions please make sure to check the documentation for Pairs and List in the racket documentation: https://docs.racket-lang.org/guide/Pairs__Lists__and_Racket_Syntax.html it is really helpful.