2012-10-02 2 views
2

다양한 Lisps에서 proper listnil (null 값) 또는 cons 셀 중 하나입니다. 여기서 첫 번째 (head, first, car) 값은 값을 가리키고 두 번째 (tail, rest , cdr) 다른 적절한 목록을 가리 킵니다. 얼랭 (Erlang)과 스칼라 (Scala)를 포함하여 다양한 다른 함수형 프로그래밍 언어가이 머리말과 꼬리 기능을 구현합니다.파이썬의 적절한 목록과 재귀 꼬리

(rest (rest (rest (rest (rest (rest())))))) 

그것은 nil을 얻을 것입니다 : 커먼 리스프와 이맥스 리스프에서는 무한 재귀리스트의 꼬리를 찾을 수 있습니다. 파이썬에서 그 동작을 에뮬레이트하고 싶습니다. 물론, 성능을 위해 나는 많이 최적화 된 원시 데이터 유형을 사용하는 것이 좋을 것입니다. 그래서 이것은 단지 운동을위한 것입니다. 내 코드는 다음과 같습니다

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를 호출

이제 최대 재귀 깊이 오류의 재귀 결과를 입력합니다. 아래 표현을 어떻게 만들 수 있습니까? 즉, 파이썬에서 적절한 목록의 기능을 어떻게 만들 수 있습니까?

a = MyList(1,2) 
my_list.tail.tail.tail.tail.tail.tail 

관련 질문,하지만 내 질문에 대답하지 않는다 : 나는 당신의 예를 조금 재 작성하려고했습니다 LISP cons in python

답변

2

-이 스택을 불어없이 나를 위해 작동하는 것 같다합니다. 당신이 무한히 목록의 tail 속성을 가져올 수 있도록하려면

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 
0

, 당신은 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 
# [] 
+0

왜 '꼬리'에 if/else가 필요한가요? – jfs

+0

이 예제에는 큰 런 공간이 있습니까? Asker의 예는 모든 노드에 대한 전체 목록을 복제하므로 (예 : 한 번에 한 요소를 트리밍합니다 .x 노드 목록의 경우 MyList를 구성하여 만든 목록의 전체 크기는 x * x/2. – Wug

+0

@Wug : 아니에요, 광산에는 'MyList'를 구성하기위한 커다란 런 공간이 없습니다 (asker가하지만). 꼬리는 요청할 때만 계산되기 때문에. a.tail.tail. tail.tail ...'은'.tail'의 수에 비례하여 runspace를 가지지 만, 당신의 구현이 무엇이든 관계없이 true가 될 것입니다 (각'.tail '이 그것의 자신의리스트가 될 것을 요구하기 때문에) –

2

오히려 클래스를 생성합니다 (lisps이 인 요소와 다음 노드를 포함하는 노드의 사슬을 작동 무엇을 기본적으로하는 (어쩌면 당신이 당신의 자신의 연결리스트를 작성해야, 목록에 바인딩하는 것보다 이는) 목록의 나머지 부분을 나타냅니다

내 파이썬은 약간 녹슨하지만 난 그것에 찔린 만들어 줄게이 의사 생각해..

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 
+0

이것은 전달 된 목록을 인수로 수정하거나 저장하지 않으며, 노드를 생성 할 때 요소를 읽은 다음 잊어 버린다는 점에 유의하십시오. – Wug

관련 문제