有这个程序给我带来麻烦:
(define (pro lst)
(define (inner l)
(if (null? (mcdr l))
(set-mcdr! l lst)
(inner (mcdr l))))
(inner lst)
lst)
使用(mlist 1 2 3)作为参数我得到#0 = {1 2 3。 #0#}返回。
(mcdr (pro (mlist 1 2 3)))
返回#0 = {2 3 1。 #0#},
(mcdr (mcdr (pro (mlist 1 2 3))))
返回#0 = {3 1 2。 #0#}等等。
显然,这是通过返回一对列表和另一个过程来循环遍历列表。但这是如何工作的?我只看到它用参数lst替换最后的'(),但没有任何模糊的lambda函数... 无论如何,#0和#0#意味着什么?
答案 0 :(得分:2)
#0=
表示某些数据的共享标记,#0#
表示对先前标记的数据的引用。请参阅http://docs.racket-lang.org/reference/shared.html底部的示例。你的函数不会返回一对东西,只返回一个值 - 定义正文中的最后一个表达式,即lst。但是,正如您可能已经意识到的那样,最后的lst
可能已经发生了变异,因此它与最初传递给函数时的变化不同。 (你使用的术语是“循环”,这正是这个功能所做的,但不是你在你的问题中应用它的意义上的。)
答案 1 :(得分:2)
在表达式#0={1 2 3 . #0#}
中,将#0=
视为锚点,将#0#
视为该锚点的链接 - 也就是说,在列表中前三个元素为{{1}但第四个元素是指向列表开头的指针,因此形成一个三元素循环列表。如果你继续推进该列表(通过连续的1 2 3
),你将在循环模式mcdr
中看到一个三元素列表,总是显示第四个元素跳回到第一个元素。
研究上述功能可以清楚地说明为什么会这样。 1 2 3 1 2 3 ...
过程只需在pro
参数上调用inner
(一个正确的列表,一个以lst
作为最后一个元素的列表),然后返回修改后的null
,有趣的部分是lst
:
inner
:如果我们在列表的最后一个非null元素上,则通过对第一个元素的引用替换下一个元素(在适当的列表中应该是(if (null? (mcdr l))
)我们知道的元素在null
参数中:lst
(set-mcdr! l lst)
总结一下:(inner (mcdr l))
过程将输入一个正确的列表并返回相同的列表,但最后一个元素指向其第一个元素 - 循环列表。