순전히 기능적인 프로그래밍의 효율성


397

누구든지 명령형이 아닌 순전히 기능적으로 프로그래밍 할 때 발생할 수있는 최악의 점근 적 둔화가 무엇인지 알고 있습니까 (예 : 부작용 허용)?

itowlson에 의한 주석의 설명 : 가장 잘 알려진 비파괴 알고리즘이 가장 잘 알려진 파괴 알고리즘보다 무질서하게 악화 되는 문제가 있습니까?


6
꼭 필요한 프로그래밍을 할 때와 동일합니다.
R. Martinho Fernandes 2012 년

3
@jldupont : 물론 계산 결과를 반환합니다. 많은 부작용이없는 프로그램이 존재합니다. 입력에 대한 계산 이외의 다른 작업은 수행 할 수 없습니다. 그러나 여전히 유용합니다.
jalf

24
기능 코드를 잘못 작성하여 원하는만큼 나쁘게 만들 수 있습니다! * 그린 * 나는 당신이 묻는 것은 "가장 잘 알려진 비파괴 알고리즘이 가장 잘 알려진 파괴 알고리즘보다 무질서하게 악화되는 문제가 있는가?"라고 생각합니다. ?
itowlson

2
관심있는 둔화 유형의 예를들 수 있습니까? 질문은 약간 모호합니다.
피터 Recore

5
사용자가 자신의 답변을 삭제했지만 8 퀸즈 문제의 기능 버전이 n = 13 분 동안 1 분 이상 실행되었다고 주장했습니다. 그는 "매우 잘 작성되지 않았다"고 인정하고 F 번호 8 여왕 : pastebin.com/ffa8d4c4 . 말할 것도없이, 순수 함수 프로그램은 1 초에 n = 20을 계산합니다.
Juliet

답변:


531

Pippenger [1996] 에 따르면 , 순전히 기능적이며 (평가 게으름이 아닌 엄격한 평가 의미를 갖는) Lisp 시스템을 데이터를 돌연변이시킬 수있는 시스템과 비교할 때 O ( n ) 에서 실행되는 불순한 Lisp에 대해 작성된 알고리즘을 변환 할 수 있습니다 O에서 실행 (즉 순수한 리스프의 알고리즘 N 로그 N 시간 ()에 기초하여 작업 벤 아므람과 Galil [1,992] 전용 포인터를 사용하여 랜덤 액세스 메모리에 대한 시뮬레이션). Pippenger는 또한 여러분이 할 수있는 최선의 알고리즘이 있음을 확립합니다. 순수한 시스템에서는 Ω ( n log n ) 인 불순 시스템 에는 O ( n )의 문제가 있습니다 .

이 논문에 대해 몇 가지주의 사항이 있습니다. 가장 중요한 것은 Haskell과 같은 게으른 기능적 언어를 다루지 않는다는 것입니다. Bird, Jones and De Moor [1997] 는 Pippenger가 구성한 문제가 O ( n ) 시간 에 게으른 기능 언어로 해결 될 수 있지만, 게으른 기능적 언어는 돌연변이가있는 언어와 동일한 점근 적 실행 시간의 모든 문제를 해결할 수 없습니다.

Pippenger가 구성한 문제는 Ω ( n log n )이이 결과를 달성하기 위해 구체적으로 구성되며 실제 실제 문제를 나타내는 것은 아닙니다. 약간 예상치 못한 문제에 대한 몇 가지 제한 사항이 있지만 증명이 작동하는 데 필요합니다. 특히, 문제는 미래의 입력에 접근 할 수없는 결과가 온라인으로 계산되고 입력이 고정 된 크기 세트가 아닌 무한한 가능한 원자 세트로부터의 원자 시퀀스로 구성되어야한다는 것을 요구한다. 그리고 논문은 선형 실행 시간의 불순한 알고리즘에 대해서만 결과를 설정합니다 (하한). 더 긴 실행 시간이 필요한 문제의 경우 추가 O (log n) 선형 문제에서 나타나는 계수는 실행 시간이 더 큰 알고리즘에 필요한 추가 작업 프로세스에서 "흡수"될 수 있습니다. 이러한 설명과 공개 된 질문은 Ben-Amram [1996]에 의해 간략히 탐구됩니다 .

실제로, 많은 알고리즘은 가변 데이터 구조를 가진 언어와 동일한 효율로 순수한 기능 언어로 구현 될 수 있습니다. 순전히 기능적인 데이터 구조를 효율적으로 구현하기 위해 사용하는 기술에 대한 좋은 참고 자료는 Chris Okasaki의 "순수한 기능적 데이터 구조"[Okasaki 1998] (그 논문의 확장 된 버전 [Okasaki 1996] )를 참조하십시오.

순전히 기능적인 데이터 구조에 알고리즘을 구현해야하는 사람은 오카 사키를 읽어야합니다. 균형 잡힌 이진 트리를 사용하여 가변 메모리를 시뮬레이트하여 작업 당 항상 O (log n ) 속도 저하를 겪을 수 있지만 대부분의 경우 그보다 훨씬 더 잘 수행 할 수 있습니다. 할부 상환을하는 사람은 점진적으로 일합니다. 순전히 기능적인 데이터 구조는 작업 및 분석이 약간 어려울 수 있지만 컴파일러 최적화, 병렬 및 분산 컴퓨팅 및 버전 관리, 실행 취소 및 롤백과 같은 기능 구현에 도움이되는 참조 투명성과 같은 많은 이점을 제공합니다.

또한이 모든 것은 점근 적 실행 시간 만 설명합니다. 순전히 기능적인 데이터 구조를 구현하는 많은 기술은 작동에 필요한 추가 부기 및 해당 언어의 구현 세부 사항으로 인해 일정한 양의 일정한 요소 속도 저하를 제공합니다. 순전히 기능적인 데이터 구조의 이점은 이러한 일정한 요소 속도 저하를 능가 할 수 있으므로 일반적으로 문제의 문제에 따라 균형을 조정해야합니다.

참고 문헌


50
Pippinger는이 질문에 대한 확실한 권위입니다. 그러나 우리는 그의 결과가 이론적 이지 않고 실용적이지 않다는 것을 강조해야한다 . 기능적 데이터 구조를 실용적이고 효율적으로 만드는 데있어 오카 사키보다 더 나은 방법은 없습니다.
노먼 램지

6
itowlson : 귀하의 질문에 답변 할 Pippenger를 충분히 읽지 못했다는 것을 인정해야합니다. 오카 사키가 인용 한 동료 검토 저널에 실 렸으며, 그의 주장이이 질문과 관련이 있지만 그 증거를 이해하기에는 충분하지 않다고 판단 할만큼 충분히 읽었습니다. 실제 결과에 대한 즉각적인 결론은 균형 잡힌 이진 트리를 사용하여 수정 가능한 메모리를 단순히 시뮬레이션 하여 O ( n ) 불순 알고리즘을 O ( n log n ) 순수한 알고리즘으로 변환하는 것이 쉽지 않다는 것 입니다. 그보다 더 잘할 수없는 문제가 있습니다. 그것들이 순전히 이론적인지 모르겠습니다.
브라이언 캠벨

3
Pippenger 결과는 범위를 제한하는 두 가지 중요한 가정을합니다. "온라인"또는 "반응 적"계산 (유일한 입력에 단일 입력을 매핑하는 계산의 일반적인 모델이 아님)과 입력이 일련의 입력 인 "기호"계산을 고려합니다. 원자는 동일성에 대해서만 테스트 될 수 있습니다 (즉, 입력의 해석은 매우 원시적입니다).
Chris Conway

2
아주 좋은 답변; 순전히 기능적인 언어의 경우 컴퓨팅 복잡성에 대해 보편적으로 합의 된 모델이 없으며 불순한 세계에서는 단가 RAM 시스템이 상대적으로 표준이기 때문에 (비교를 어렵게 만듭니다) 추가하고 싶습니다. 또한 순수 / 불완전한 Lg (N) 차이의 상한은 순수 언어로 배열의 구현을 보면 직관적으로 매우 쉽게 설명 할 수 있습니다 (작업 당 lg (n) 비용 (그리고 당신은 역사를 얻습니다)) .
user51568

4
중요한 점 : 순전히 기능 사양을보다 복잡하고 효율적으로 순전히 구현 하는 것으로 순식간에 번역하는 것은 궁극적으로 자동 또는 수동으로 더 효율적인 불순 코드로 변환하려는 경우에는 별 도움이되지 않습니다. 케이지에 담을 수 있다면 불순물은 그다지 중요하지 않습니다. 예를 들어 외부에 영향을주지 않는 기능으로 잠급니다.
Robin Green

44

게으름에도 불구하고 무의식적으로 효율적인 순수 기능 솔루션 (순수 람다 미적분에서 구현 가능한 솔루션)이 알려지지 않은 몇 가지 알고리즘과 데이터 구조가 있습니다.

  • 앞서 언급 한 노조 찾기
  • 해시 테이블
  • 배열
  • 일부 그래프 알고리즘
  • ...

그러나, 우리는 "불완전한"언어에서 메모리에 대한 접근은 O (1) 인 반면 이론 상으로는 무의식적으로 (즉, 무한한 문제 크기에 대해) 불가능하고 거대한 데이터 세트 내의 메모리에 대한 접근은 항상 O (log n)라고 가정합니다. 기능 언어로 에뮬레이트 할 수 있습니다.

또한 실제로 모든 현대 기능 언어는 변경 가능한 데이터를 제공하며 Haskell은 순도 (ST 모나드)를 희생하지 않고 제공합니다.


3
데이터 세트가 실제 메모리에 맞는 경우, 항목을 읽는 시간에 대한 절대 상한을 찾을 수 있다는 점에서 데이터 액세스는 O (1)입니다. 데이터 세트가 없으면 I / O에 대해 이야기하고 있으며 이것이 그 주요한 요인이 될 것이지만 프로그램이 작성되었습니다.
Donal Fellows

물론, 나는 외부 메모리에 액세스하는 O (log n) 연산에 대해 이야기하고 있습니다. 그러나, 어떤 경우에 내가 말하고 기지국은 : 외부 메모리는 O (1) - 주소 지정 될 수 ...
JKFF

2
필연적으로 함수형 프로그래밍과 비교할 때 명령형 프로그래밍이 얻는 가장 큰 장점 중 하나는 한 상태의 여러 가지 독특한 측면에 대한 참조를 보유하고 모든 참조가 새로운 상태의 해당 측면을 가리 키도록 새로운 상태를 생성하는 능력입니다. 함수형 프로그래밍을 사용하려면 직접 역 참조 작업을 조회 작업으로 대체하여 현재 전체 상태의 특정 버전의 적절한 측면을 찾으십시오.
supercat 2016 년

포인터 모델 (O (log n) 메모리 액세스, 느슨하게 말해서)조차도 매우 큰 규모에서는 물리적으로 현실적이지 않습니다. 빛의 속도는 서로 다른 컴퓨팅 장비들이 서로 얼마나 빨리 통신 할 수 있는지를 제한하는 한편 , 주어진 영역에 보유 될 수있는 최대 정보량은 표면적에 의해 제한되는 것으로 현재 알려져 있다.
dfeuer

36

이 기사 는 노조 찾기 알고리즘 의 알려진 기능 구현은 모두 게시 한 것보다 더 복잡한 점증 적 복잡성을 가지며, 기능적으로 순수한 인터페이스를 가지고 있지만 내부적으로 변경 가능한 데이터를 사용 한다고 주장합니다 .

다른 답변에 차이가 없다고 주장한다는 사실과, 예를 들어 순수하게 기능적인 코드의 유일한 "단점"은 병렬화 될 수 있다는 것입니다. .

편집하다:

아래의 의견은 순수한 기능적 프로그래밍의 장단점에 대한 편견은“기능적 프로그래밍 커뮤니티”에서 나오지 않을 수 있다고 지적합니다. 좋은 지적. 아마도 내가 옹호하는 사람들은 단지“완화”라는 의견을 인용하는 것일뿐입니다.

예를 들어,이 블로그 게시물 은 함수형 프로그래밍 커뮤니티를 대표한다고 할 수있는 사람이 작성한 것으로 생각 되며 "게으른 평가를위한 포인트"목록이므로 다음과 같은 단점을 언급 할 수 있습니다. 게으르고 순전히 기능적인 프로그래밍이있을 수 있습니다. 좋은 장소는 다음과 같은 장소에 있었을 것입니다 (기술적으로는 맞지만 재미 있지 않은 지점으로 편향 됨).

엄격한 함수가 엄격한 언어에서 O (f (n)) 복잡도를 갖는 경우 게으른 언어에서도 복잡도 O (f (n))가 있습니다. 왜 걱정? :)


4

메모리 사용에 대한 상한이 고정되어 있으면 차이가 없어야합니다.

프루프 스케치 : 메모리 사용에 대한 고정 된 상한이 주어지면 실제 머신에서 실제로 실행하는 것과 동일한 점근 적 복잡도로 명령형 명령 세트를 실행하는 가상 머신을 작성할 수 있어야합니다. 변경 가능한 메모리를 영구 데이터 구조로 관리하여 O (log (n))에 읽기 및 쓰기를 제공 할 수 있지만 메모리 사용에 대한 상한이 고정되어 있으면 고정 된 양의 메모리를 가질 수 있으므로 O (1)로 붕괴합니다. 따라서 기능 구현은 VM의 기능 구현에서 실행되는 명령 버전 일 수 있으므로 둘 다 동일한 점근 적 복잡성을 가져야합니다.


6
메모리 사용에 대한 고정 된 상한은 사람들이 이런 종류의 것들을 분석하는 방식이 아닙니다. 당신은 임의로 크지 만 유한 한 메모리를 가정합니다. 알고리즘을 구현할 때 가장 간단한 입력에서 임의의 입력 크기까지 확장하는 방법에 관심이 있습니다. 메모리 사용에 고정 상한을 설정하면 계산에 걸리는 시간에 고정 상한도 설정하고 모든 것이 O (1)라고 말하지 않겠습니까?
Brian Campbell

@Brian Campbell : 사실입니다. 나는 당신이 원한다면 실제로 많은 경우에 상수 요소의 차이를 무시할 수 있다고 제안합니다. 메모리와 시간을 훼손 할 때 m 배 더 많은 메모리를 사용하면 런타임이 최소한 log (m)의 인자만큼 감소되도록하기 위해 여전히 차이를 염두에 두어야합니다.
Brian

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