Python中的正确列表和递归尾部

时间:2012-10-02 17:33:19

标签: python cons cdr

在各种Lisp中,proper listnil(空值)或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

3 个答案:

答案 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
# []