在各种Lisp中,proper list是nil
(空值)或cons单元格,其中第一个(头部,第一个,汽车)值指向一个值,第二个(尾巴,休息,cdr)指向另一个正确的列表。各种其他函数式编程语言实现了这种头尾功能,包括Erlang和Scala。在Common Lisp和Emacs Lisp中,您可以无限递归地查找列表的尾部:
(rest (rest (rest (rest (rest (rest ()))))))
它会产生nil
。我想在Python中模仿这种行为。当然,为了性能,我最好坚持使用本机数据类型,这些数据类型经过了大量优化,所以这只适用于练习。我的代码是:
class MyList:
def __init__(self, *xs):
self._x = []
self._x.extend(xs)
self.is_empty = not xs
self.head = xs[0] if xs else None
self.tail = MyList(*xs[1:]) if xs[1:] else MyList([])
然而,调用tail
现在进入递归并导致最大递归深度错误。我怎样才能使下面的表达成为可能呢?换句话说,我如何在Python中创建适当列表的功能?
a = MyList(1,2)
my_list.tail.tail.tail.tail.tail.tail
相关问题,但未回答我的问题:LISP cons in python
答案 0 :(得分:2)
我尝试过重写一下你的例子 - 这似乎对我有用而没有吹掉堆栈。
class MyList(object):
def __init__(self, *xs):
self._x = xs if all(xs) else tuple()
self.head = xs[0] if xs else None
@property
def is_empty(self):
return not self._x
@property
def tail(self):
return MyList(self._x[1:]) if self._x[1:] else MyList([])
s = MyList(1, 2)
print s.tail.tail.tail.tail.tail.tail
答案 1 :(得分:2)
不是尝试创建类并将其绑定到列表,也许您应该编写自己的链表(这基本上是lisps使用的,包含元素的节点链和下一个节点(代表其余节点)列表)。
我的python有点生疏,但我会捅它。考虑这个伪代码:
class WugList:
def __init__(self, *xs):
self.head = xs[0] if (len(xs) > 0) else None
self.tail = WugList(xs[1:]) if (len(xs) > 0) else self
self.is_empty = (len(xs) > 0)
def car(self):
return self.head
def cdr(self):
return self.tail
然后您应该可以使用以下内容:
derp = WugList([1,2,3,42,69,9001])
a = derp.car() # 1
b = derp.cdr().car() # 2
c = derp.cdr().cdr().cdr().car() # 42
# chaining cdr infinitely is possible because the last node's head is None
# and its tail is itself
d = derp.cdr().cdr().cdr().cdr().cdr().cdr().cdr().cdr().cdr().cdr()
.cdr().cdr().cdr().cdr().cdr().cdr().cdr().cdr().cdr()
.cdr().cdr().cdr().cdr().cdr().cdr().cdr().cdr().car() # None
答案 2 :(得分:0)
如果您希望能够无限地获取列表的tail
属性,则需要使用property
。这样,在你要求它之前不会评估尾部,这会阻止无限递归。
class MyList:
def __init__(self, *xs):
self._x = []
self._x.extend(xs)
self.is_empty = not xs
self.head = xs[0] if xs else None
@property
def tail(self):
return MyList(*self._x[1:])
a = MyList(1,2)
print a._x
# [1, 2]
print a.tail._x
# [2]
print a.tail.tail._x
# []
print a.tail.tail.tail._x
# []
print a.tail.tail.tail.tail._x
# []