함수형 프로그래밍의 상태 문제 처리


18

나는 주로 OOP 관점에서 프로그래밍하는 방법을 배웠지 만 (우리 대부분과 마찬가지로) 나는 문제를 기능적으로 해결하는 방법을 배우려고 많은 시간을 보냈습니다. FP로 계산 문제를 해결하는 방법을 잘 알고 있지만 더 복잡한 문제가 발생하면 항상 변경 가능한 객체가 필요한 것으로 되돌아갑니다. 예를 들어, 입자 시뮬레이터를 작성하는 경우 변경 가능한 위치의 입자 "개체"를 업데이트하려고합니다. 기능적 프로그래밍 기술을 사용하여 본질적으로 "상태 저장"문제를 해결하는 방법은 무엇입니까?


4
첫 번째 단계는 문제가 본질적으로 상태가 아님을 깨닫는 것입니다.
Telastyn

4
데이터베이스에 쓰거나 GUI를 그리는 것과 같은 일부 문제는 본질적으로 상태가 양호합니다. 파티클 시뮬레이터 예제를 생각해 보면 대안으로 생각할 수있는 방법은 무엇입니까? 상태를 피하기 위해 위치가 업데이트 될 때마다 새로운 입자를 반환하는 것은 비효율적이며 실제 세계의 좋은 모델은 아닙니다.
Andrew Martin

4
데이터베이스 예제를 제외하고는 이러한 문제는 본질적으로 상태 가 아닙니다 . 예를 들어, GUI 프로그래밍의 경우, 가변 상태를 가난하고 암시적인 시간 모델로 사용하고 있습니다 . 기능적 반응성 프로그래밍을 사용하면 결합 할 수있는 이벤트 스트림을 제공하여 상태에 의존하지 않고 명시 적으로 시간을 모델링 할 수 있습니다.
Tikhon Jelvis

1
더 간단한 해결책이 있습니다. FP 기술로 쉽게 모델링되지 않는 문제가 발생 하면 함수형 프로그래밍을 사용하여 해결하지 마십시오. 직업과 모든 것을위한 올바른 도구 ...
Mason Wheeler

1
@AndrewMartin 실세계의 좋은 모델이 아니십니까? 실제 세계를 모델링하기 위해 물리학에서 사용되는 수학은 순전히 기능적입니다. 가비지 수집기가 잘 있으면 개체를 할당하는 것이 포인터를 부딪 치는 것만 큼 저렴하며 수집 시간은 실제 개체 수에 비례 합니다. 기능 프로그래밍에서 비 효율성의 주요 원인은 캐시 효율적이지 않은 데이터 구조를 사용하는 것입니다. 연결된 목록과 이진 트리는 캐시 효율성의 하위 요소가 아닙니다.
Doval

답변:


20

기능적 프로그램은 상태를 매우 잘 처리하지만 다른 방식으로 볼 필요가 있습니다. 위치 예를 들어, 고려해야 할 사항은 위치가 고정 된 값 대신 시간의 함수가되도록하는 것입니다 . 고정 된 수학적 경로를 따르는 입자에는 효과적이지만 충돌 후와 같이 경로의 변화를 처리하기위한 다른 전략이 필요합니다.

여기서 기본 전략은 상태를 가져 와서 새로운 상태를 반환하는 함수를 만드는 것입니다 . 따라서 입자 시뮬레이터는 Set입자를 입력으로 받아 Set시간 단계 후에 새로운 입자를 반환하는 함수입니다 . 그런 다음 입력을 이전 결과로 설정하여 해당 함수를 반복적으로 호출합니다.


5
+1 변경 가능 상태가 아닌 FP에 상태가 있으면 괜찮습니다 .
jhewlett 2016 년

1
이 통찰력에 감사드립니다. 비 효율성에 대한 걱정은 @logc에 의해 좌절되었습니다. 상태가 어떻게 변환되는지에 대한 기술적 세부 사항은 언어 자체가 해결해야 할 저수준 구현 문제입니다. Rich Hickey가 Clojure를 어떻게 사용하는지 비디오에서 설명하는 것을 보았습니다.
Andrew Martin

1
@jhewlett : 더 정확하게 말하면 : FP에는 상태, 심지어 변경 가능한 상태가 있지만 변경 가능한 변수를 사용하여 나타내지는 않습니다.
Giorgio

9

@KarlBielefeldt가 지적한 것처럼, 이러한 문제에 대한 기능적 접근 방식은 이전 상태에서 새로운 상태를 반환하는 것으로 보는 것입니다. 함수 자체는 정보를 보유하지 않으므로 항상 상태 m 을 상태 n으로 업데이트 합니다.

새 상태를 계산하는 동안 이전 상태 를 메모리에 유지 해야한다고 가정하기 때문에이 비효율적이라고 생각합니다 . 완전히 새로운 상태를 작성하거나 이전 상태를 다시 작성하는 것 중에서 선택 하는 것은 기능적 언어의 관점에서 구현 세부 사항 입니다.

예를 들어, 백만 개의 정수 목록이 있고 10 분의 1을 증가시키고 싶다고 가정하십시오. 10 번째 위치에 새로운 번호로 전체 목록을 복사하는 것은 낭비입니다. 그러나 이는 언어 컴파일러 또는 인터프리터에게 작업을 설명하는 개념적 방법 일뿐입니다. 컴파일러 또는 인터프리터는 첫 번째 목록을 자유롭게 가져 와서 열 번째 위치를 덮어 씁니다.

이러한 방식으로 작업을 설명하는 이점은 많은 스레드가 다른 위치에서 동일한 목록을 업데이트하려고 할 때 컴파일러가 상황에 대해 추론 할 수 있다는 것입니다. 작업이 "이 위치로 이동하여 찾은 내용을 덮어 씁니다"로 설명 된 경우 덮어 쓰기가 충돌하지 않도록하는 것은 컴파일러가 아닌 프로그래머입니다.

그러나 Haskell에도 "상태 유지"가 문제에 대한보다 직관적 인 솔루션 인 상황을 모델링하는 데 도움 이되는 State 모나드 가 있습니다. 그러나 " 데이터베이스에 쓰는 것과 같이 본질적으로 상태양호하다 "는 Datomic과 같은 불변의 솔루션 이 있다는 몇 가지 문제에 주목하십시오 . 개념이라는 것을 알기 전까지는 반드시 실현 될 필요는 없습니다.


4
큰 목록을 업데이트하는 것에 대한 스 니펫이 잘못되었다고 생각합니다. 나는 실제로 당신을 위해 그 최적화를 수행 할 컴파일러를 모른다. 컴파일러가 그렇게 할 수 있더라도 이전 버전의 목록을 유지하지 않는 경우에만 가능합니다. 실제 솔루션은 하나의 요소를 변경하려면 전체를 복사 할 필요가없는 목록 데이터 구조를 사용하는 것입니다.
Doval

@Doval : "컴파일러가 그렇게해도 목록의 이전 버전을 유지하지 않는 경우에만 가능합니다.": Clean의 고유 한 유형을 생각 나게합니다.
Giorgio

4

올바른 정신 모델을 구독하면 상태를 더 잘 생각하고 관리하는 데 도움이됩니다. 내 마음에, 최고의 정신 모델은 플립 북 입니다. 클릭하면 FP가 세계 상태를 캡처하는 영구적 인 데이터 구조에 크게 의존하고 있으며 함수가 돌연변이없이 해당 상태를 전환하는 데 사용된다는 것을 이해할 수 있습니다.

Rich Hickey는 다음 아이디어를 밝힙니다.

다른 이야기입니다 그러나 이것은 옳은 방향으로 당신을 보내야합니다.


3

크고 중간 규모의 응용 프로그램을 작성할 때 종종 상태 기반 응용 프로그램과 상태 비 저장 응용 프로그램 섹션을 구분하는 것이 유용하다는 것을 알았습니다.

상태 저장 섹션의 클래스 / 데이터 구조는 응용 프로그램 데이터를 저장하며이 섹션의 기능은 응용 프로그램 데이터에 대한 암시 적 지식으로 작동합니다.

상태 비 저장 섹션의 클래스 / 데이터 구조 / 함수는 애플리케이션의 순전히 알고리즘 측면을 지원하기 위해 존재합니다. 그들은 응용 프로그램의 데이터에 대한 암시 적 지식이 없습니다. 그것들은 순전히 기능적인 성격으로 작동합니다. 응용 프로그램의 상태 저장 부분은 응용 프로그램의 상태 비 저장 섹션에서 함수 실행의 부작용으로 상태 변경을 경험할 수 있습니다.

가장 어려운 부분은 stateless 섹션에 넣을 클래스 / 함수와 stateful 섹션에 넣을 클래스 / 함수를 파악하고 별도의 파일 / 라이브러리에 넣는 규칙을 갖는 것입니다.


이 질문에 어떻게 대답합니까? (비공개)
kravemir

@kravemir, OOP를 사용하여 응용 프로그램을 작성하든 FP를 사용하든 응용 프로그램의 상태가 어디에 있는지 이해해야합니다.
R Sahu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.