함수형 프로그래밍 언어는 부작용을 허용하지 않습니까?


10

선언적인 기능적 프로그래밍 언어 인 Wikipedia에 따르면 부작용을 허용하지 않습니다. 일반적으로 선언적 프로그래밍 은 부작용을 최소화하거나 제거하려고 시도합니다.

또한 Wikipedia에 따르면 부작용은 상태 변경과 관련이 있습니다. 따라서 기능적 프로그래밍 언어는 그런 의미에서 상태를 저장하지 않기 때문에 실제로 부작용을 제거합니다.

그러나 부작용 에는 또 다른 정의가 있습니다. 부작용

값을 반환하는 것 외에도 호출 함수 또는 외부 세계와 관찰 가능한 상호 작용이 있습니다. 예를 들어, 특정 함수는 전역 변수 또는 정적 변수를 수정하거나, 인수 중 하나를 수정하거나, 예외를 발생 시키거나, 데이터를 디스플레이 나 파일에 쓰거나, 데이터를 읽거나, 다른 부작용을 일으키는 함수를 호출 할 수 있습니다.

그런 의미에서 함수형 프로그래밍 언어는 실제로 외부 세계에 영향을 미치는 함수, 다른 함수 호출, 예외 발생, 파일 쓰기 등의 수많은 예제가 있기 때문에 실제로 부작용을 허용합니다.

마지막으로, 기능적 프로그래밍 언어는 부작용을 허용합니까?

또는 "부작용"의 자격이 무엇인지 이해하지 못하므로 명령형 언어로 허용하고 선언적으로는 허용하지 않습니다. 위와 내가 얻는 것에 따르면, 언어가 부작용을 제거하지 않으므로 부작용에 대한 정보가 누락되었거나 Wikipedia 정의가 잘못되었습니다.

답변:


26

함수형 프로그래밍에는 다양한 기술이 포함됩니다. 일부 기술은 부작용이 있습니다. 그러나 중요한 측면은 방정식 추론입니다 . 같은 값으로 함수를 호출하면 항상 같은 결과를 얻습니다. 따라서 함수 호출을 반환 값으로 대체하고 동등한 동작을 얻을 수 있습니다. 이를 통해 특히 디버깅 할 때 프로그램에 대해 추론하기가 더 쉬워집니다.

함수에 부작용이 있다면, 이것은 잘 유지되지 않습니다. 반환 값에는 부작용이 없으므로 반환 값은 함수 호출과 동일하지 않습니다.

용액의 사용을 중지하는 효과 이러한 효과 인코딩 리턴 값을 . 언어마다 효과 시스템이 다릅니다. 예를 들어 Haskell은 모나드를 사용하여 IO 또는 상태 돌연변이와 같은 특정 효과를 인코딩합니다. C / C ++ / Rust 언어에는 일부 값의 돌연변이를 허용하지 않는 유형 시스템이 있습니다.

명령형 언어에서 print("foo")함수는 무언가를 인쇄하고 아무것도 반환하지 않습니다. Haskell과 같은 순수 기능 언어에서 print함수는 외부 세계의 상태를 나타내는 객체를 가져 와서이 출력을 수행 한 후 상태를 나타내는 새 객체를 반환합니다. 와 비슷한 것 newState = print "foo" oldState입니다. 이전 상태에서 원하는만큼 새 상태를 만들 수 있습니다. 그러나 기본 기능에는 하나만 사용됩니다. 따라서 함수를 연결하여 여러 작업의 상태를 시퀀싱해야합니다. 인쇄하려면 foo bar다음과 같이 말할 수 있습니다 print "bar" (print "foo" originalState).

출력 상태가 사용되지 않으면 Haskell은 게으른 언어이므로 해당 상태로 이어지는 작업을 수행하지 않습니다. 반대로이 게으름은 모든 효과가 명시 적으로 반환 값으로 인코딩되기 때문에 가능합니다.

Haskell 은이 경로를 사용 하는 유일한 통용 언어입니다. 기타 기능 언어 포함 Lisp 계열, ML 계열 및 Scala와 같은 최신 기능 언어는 낙관적이지만 여전히 부작용을 허용합니다. 명령형 기능 언어라고 할 수 있습니다.

I / O에 대한 부작용을 사용하는 것이 좋습니다. 종종 I / O (로깅 제외)는 시스템의 외부 경계에서만 수행됩니다. 비즈니스 논리 내에서 외부 통신이 발생하지 않습니다. 그러면 외부 쉘에서 여전히 불완전한 I / O를 수행하면서 소프트웨어의 핵심을 순수한 스타일로 작성할 수 있습니다. 이것은 또한 핵심이 무국적 일 수 있음을 의미합니다.

상태 비 저장은 합리성 및 확장 성 향상과 같은 여러 가지 실질적인 이점이 있습니다. 이것은 웹 애플리케이션 백엔드에 매우 인기가 있습니다. 모든 상태는 공유 데이터베이스에서 외부로 유지됩니다. 이렇게하면로드 밸런싱이 쉬워집니다. 세션을 특정 서버에 고정시킬 필요가 없습니다. 서버가 더 필요한 경우 어떻게합니까? 동일한 데이터베이스를 사용하고 있으므로 다른 것을 추가하십시오. 하나의 서버가 충돌하면 어떻게됩니까? 다른 서버에서 보류중인 요청을 다시 실행할 수 있습니다. 물론 데이터베이스에는 여전히 상태가 있습니다. 그러나 나는 그것을 명시 적으로 만들고 추출했으며, 원한다면 내부적으로 순수한 기능적 접근 방식을 사용할 수 있습니다.


자세한 답변 주셔서 감사합니다. 결론으로 유지하는 것은 방정식 추론으로 인해 부작용이 함수 값에 영향을 미치지 않는다는 것입니다. 이것이 바로 함수형 언어가 부작용을 허용 / 최소화하지 않는 이유입니다. 함수 값에 포함 된 효과는 저장되거나 프로그램의 핵심 외부에 저장된 상태에 영향을 미치고 변경됩니다. 또한 I / O는 비즈니스 로직의 외부 경계에서 발생합니다.
codebot

3
내 의견으로는 @codebot이 아닙니다. 제대로 구현되면 함수형 프로그래밍의 부작용이 함수의 반환 유형에 반영되어야합니다. 예를 들어, 함수가 실패 할 수있는 경우 (특정 파일이 없거나 데이터베이스 연결을 설정할 수없는 경우) 함수가 예외를 발생시키지 않고 함수의 리턴 유형이 실패를 캡슐화해야합니다. 예를 들어 철도 지향 프로그래밍 ( fsharpforfunandprofit.com/posts/recipe-part2 )을 살펴보십시오 .
Aaron M. Eshbach

"... 명령형 함수형 언어라고 할 수 있습니다.": Simon Peyton Jones는 "... Haskell은 세계 최고의 명령형 프로그래밍 언어입니다."
Giorgio

5

프로그래밍 언어 부작용을 제거 하지 않습니다 . 선언적 언어 에는 부작용이 있지만 명령형 언어 에는 부작용 이 없다고 말하는 것이 좋습니다 . 그러나 부작용에 대한이 이야기가 두 가지 언어 유형의 근본적인 차이에 도달하고 실제로 그것이 당신이 찾고있는 것처럼 보이는지 확실하지 않습니다.

예제와의 차이점을 설명하는 데 도움이된다고 생각합니다.

a = b + c

위의 코드 줄은 거의 모든 언어로 작성 될 수 있으므로 명령형 언어인지 선언 형 언어를 사용하고 있는지 어떻게 알 수 있습니까? 두 코드 클래스에서 해당 코드 줄의 속성이 어떻게 다릅니 까?

명령형 언어 (C, Java, Javascript 등)에서 해당 코드 줄은 단지 프로세스의 단계를 나타냅니다. 그것은 어떤 가치의 근본적인 본질에 대해서는 아무 것도 알려주지 않습니다. 이 코드 줄 이후 (그러나 다음 줄 이전)의 순간에는 플러스 a가 될 것이지만 더 큰 의미는 알려주지 않습니다 .bca

선언적 언어 (Haskell, Scheme, Excel 등)에서 해당 코드 줄은 훨씬 더 많은 것을 말합니다. 그것은 항상 플러스와 같은 경우가되도록 a다른 두 객체 사이의 불변 관계를 설정합니다 . 값을 변경 하거나 변경 하더라도 사실은 그대로 남아 있기 때문에 선언적 언어 목록에 Excel을 포함 시켰 습니다.abcbca

내 생각에 이것은 부작용이나 상태가 아닌 두 가지 유형의 언어를 다르게 만드는 것입니다. 명령형 언어에서 특정 코드 줄은 해당 변수의 전반적인 의미에 대해 아무 것도 알려주지 않습니다. 즉, a = b + c단지 시간의 아주 짧은 순간에 대한 것을 의미 a의 합을 동일하게 발생 b하고 c.

한편, 선언적 언어에서는 모든 코드 라인이 프로그램의 전체 수명 동안 존재할 기본 진리를 확립합니다. 이러한 언어에서는 a = b + c다른 코드 줄에서 어떤 일이 발생하더라도 a항상 b및 의 합 과 같습니다 c.

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