단점 목록이 함수형 프로그래밍과 관련된 이유는 무엇입니까?


22

대부분의 기능적 언어는 단일 연결 목록 ( "cons"목록)을 가장 기본적인 목록 유형으로 사용합니다. 예로는 Common Lisp, Haskell 및 F #이 있습니다. 이것은 기본 목록 유형이 배열 인 주류 언어와 다릅니다.

왜 그런가요?

Common Lisp (동적 타입)의 경우, 단점은 목록, 트리 등의 기반이 될만큼 일반적이라는 아이디어를 얻습니다. 이것은 작은 이유 일 수 있습니다.

정적 타입 언어의 경우, 좋은 추론을 찾을 수 없으며 반대 주장을 찾을 수도 있습니다.

  • 기능적 스타일은 불변성을 장려하므로 연결된 목록의 삽입 용이성은 이점이 아닙니다.
  • 기능적 스타일은 불변성을 권장하므로 데이터 공유도 가능합니다. 배열은 연결된 목록보다 "부분적으로"공유하기가 쉽습니다.
  • 일반 배열에서도 패턴 일치를 수행 할 수 있으며 더 좋습니다 (예를 들어 오른쪽에서 왼쪽으로 쉽게 접을 수 있음).
  • 게다가 무료로 랜덤 액세스 할 수 있습니다.
  • 언어가 정적으로 유형이 정해지면 (실용적인 이점) 정기적 인 메모리 레이아웃을 사용하고 캐시에서 속도를 높일 수 있습니다.

그렇다면 왜 링크 된 목록을 선호합니까?


4
@ sepp2k의 답변에 대한 의견에서 나는 an array is easier to share "partially" than a linked list당신이 의미하는 바를 명확히해야 한다고 생각 합니다. 재귀 적 특성으로 인해 그 반대의 경우도 마찬가지입니다. 어느 노드를 통과하여 연결된 목록을 더 쉽게 공유 할 수 있지만 배열은 새 복사본을 만드는 데 시간을 소비해야합니다. 또는 데이터 공유 측면에서 두 개의 연결된 목록이 동일한 접미사를 가리킬 수 있습니다. 이는 배열에서는 불가능합니다.
이즈 카타

배열 자체가 오프셋, 길이, 버퍼 트리플로 정의되면 offset + 1, length-1, buffer를 사용하여 새 배열을 만들어 배열을 공유 할 수 있습니다. 또는 하위 배열로 특수한 유형의 배열을 사용하십시오.
Dobes Vandermeer

@Izkata 배열에 대해 말할 때 C에서 연속 메모리의 시작에 대한 포인터와 같은 버퍼를 의미하는 경우는 거의 없습니다. 일반적으로 랩 된 버퍼의 시작에 대한 길이와 포인터를 저장하는 일종의 구조를 의미합니다. 이러한 시스템에서 슬라이싱 작업은 버퍼 배열이 하위 배열의 첫 번째 요소에서 버퍼의 중간 지점을 가리키고 시작 + 카운트가 마지막 요소를 제공하는 개수 인 하위 배열을 반환 할 수 있습니다. 이러한 슬라이싱 작업은 시간과 공간에서 O (1)입니다
Alexander-Reinstate Monica

답변:


22

가장 중요한 요소는 O (1) 시간 내에 불변의 단일 링크 목록 앞에 추가 할 수 있다는 것입니다. 이렇게하면 O (n) 시간에 n- 요소 목록을 다음과 같이 재귀 적으로 작성할 수 있습니다.

// Build a list containing the numbers 1 to n:
foo(0) = []
foo(n) = cons(n, foo(n-1))

불변 배열을 사용하여이 cons작업을 수행 한 경우 각 작업에서 전체 배열을 복사해야하기 때문에 실행 시간이 2 차가되어 2 차 실행 시간이 발생합니다.

기능적 스타일은 불변성을 권장하므로 데이터 공유도 가능합니다. 배열은 연결된 목록보다 "부분적으로"공유하기가 더 쉽습니다.

"부분적으로"공유한다는 것은 O (1) 시간에 배열에서 하위 배열을 가져올 수있는 반면 연결된 목록을 사용하면 O (1) 시간에 꼬리 만 사용할 수 있으며 다른 모든 것에는 O (n)이 필요하다는 것을 의미합니다. 사실입니다.

그러나 많은 경우 꼬리를 잡는 것으로 충분합니다. 배열을 저렴하게 만들 수있는 방법이 없다면 하위 배열을 저렴하게 만들 수 있다고해도 도움이되지 않는다는 점을 고려해야합니다. 그리고 영리한 컴파일러 최적화 없이는 어레이를 단계별로 저렴하게 구축 할 수있는 방법이 없습니다.


전혀 사실이 아닙니다. 상각 된 O (1)로 배열에 추가 할 수 있습니다.
DeadMG

10
@DeadMG 네, 그러나 불변 배열은 아닙니다 .
sepp2k

"부분적으로 공유"-두 개의 단점 목록이 동일한 접미사 목록을 가리킬 수 있고 (이를 원하는 이유는 아님) 목록을 시작하지 않고 중간 점을 복사하지 않고 다른 함수에 전달할 수 있다고 생각합니다. 그것 (나는 이것을 여러 번
했음

@Izkata OP는 목록이 아니라 배열을 부분적으로 공유하는 것에 대해 이야기했습니다. 또한 부분 공유 라고하는 내용을 들어 본 적이 없습니다 . 그것은 단지 공유입니다.
sepp2k

1
@Izkata OP는 "배열"이라는 용어를 정확히 세 번 사용합니다. FP 언어는 다른 언어가 배열을 사용하는 링크 된 목록을 사용한다고합니다. 한 번 말하면 배열은 링크 된 목록보다 부분 공유가 더 좋고 한 번은 배열도 링크 된 목록처럼 패턴 일치시킬 수 있습니다. 모든 경우에 그는 배열과 연결 목록을 대조하고 있습니다 (연결 목록보다 배열이 기본 데이터 구조로 더 유용하다는 점을 지적하기 위해 FP에서 연결 목록이 선호되는 이유에 대한 질문으로 이어짐). 용어를 서로 바꿔서 사용할 수 있습니다.
sepp2k

4

기능 코드로 쉽게 구현되는 목록이 있다고 생각합니다.

계획:

(define (cons x y)(lambda (m) (m x y)))

하스켈 :

data  [a]  =  [] | a : [a]

배열은 어렵고 구현하기가 쉽지 않습니다. 그것들이 매우 빠르기를 원한다면 저수준으로 작성되어야합니다.

또한 재귀는 배열보다 목록에서 훨씬 잘 작동합니다. 목록을 재귀 적으로 소비 / 생성 한 횟수와 배열을 인덱싱 한 횟수를 고려하십시오.


나는 당신의 계획 버전을 링크 된 목록의 구현이라고 부르는 것이 정확하다고 말하지 않을 것입니다. 기능 이외의 것을 저장하는 데 사용할 수 없습니다. 또한 배열은 배열 (또는 메모리 청크)을 기본적으로 지원하지 않는 언어로 구현하기가 더 어렵습니다 (실제로는 불가능합니다). 링크 된 목록은 구현하기 위해 구조체, 클래스, 레코드 또는 대수 데이터 유형과 같은 것만 필요합니다. 기능적 프로그래밍 언어에만 국한된 것은 아닙니다.
sepp2k

@ sepp2k "함수 이외의 것을 저장 한다 " 는 무슨 뜻 입니까?
Pubby

1
내가 의미하는 바는 그런 식으로 정의 된 목록은 함수가 아닌 것을 저장할 수 없다는 것입니다. 그러나 사실은 아닙니다. 던노, 왜 그렇게 생각해 미안합니다.
sepp2k

2

단일 연결 목록은 가장 간단한 영구 데이터 구조 입니다.

지속적인 데이터 구조는 성능이 뛰어나고 기능적인 프로그래밍에 필수적입니다.


1
이것은 단지 4 년 전에 게시 된 최고의 답변 에서 반복적으로 언급되고 설명 된 것처럼 보인다
gnat

3
@gnat : 최고 답변은 영구 데이터 구조를 언급하지 않거나 단독으로 연결된 목록이 가장 간단한 영구 데이터 구조이거나 순수하게 기능적인 프로그래밍을 수행하는 데 필수적이라는 것입니다. 나는 최고 답변과 겹치지 않습니다.
Michael Shaw

2

가비지 수집 언어가있는 경우에만 Cons 노드를 쉽게 사용할 수 있습니다.

단점 노드는 재귀 호출 및 불변 값의 기능적 프로그래밍 스타일과 많이 일치합니다. 따라서 그것은 정신 프로그래머 모델에 잘 맞습니다.

그리고 역사적인 이유를 잊지 마십시오. 왜 그들은 여전히 ​​Cons Nodes라고 불리우며 여전히 접근 자로 car와 cdr을 사용합니까? 사람들은 교과서와 과정에서 그것을 배우고 그것을 사용합니다.

실제 배열에서는 사용하기가 훨씬 쉽고 메모리 공간의 절반 만 소비하며 캐시 수준 누락으로 인해 성능이 뛰어납니다. 명령형 언어와 함께 사용할 이유가 없습니다.


1

링크 된 목록은 다음과 같은 이유로 중요합니다.

당신 후에 3과 같은 숫자를 가지고 가고, 같은 후속 순서로 변환 succ(succ(succ(zero)))한 다음에 그것을 대체를 사용 {succ=List node with some memory space}하고 {zero = end of list}있습니다 (길이 3) 연결리스트로 끝날 것이다.

실제 중요한 부분은 숫자, 대체 및 메모리 공간과 0입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.