함수형 프로그래밍에서 부작용이 왜 악의적 인 것으로 간주됩니까?


69

부작용은 자연스러운 현상이라고 생각합니다. 그러나 그것은 기능적 언어에서 금기와 같은 것입니다. 이유는 무엇입니까?

내 질문은 기능적 프로그래밍 스타일에 관한 것입니다. 모든 프로그래밍 언어 / 패러다임이 아닙니다.


6
부작용이없는 프로그램은 쓸모가 없으므로 부작용은 사악하거나 금기가 아닙니다. 그러나 FP는 부작용으로 코드를 구분하므로 코드의 대부분이 부작용이없는 기능입니다. 부작용이없는 기능 및 서브 시스템은 이해하기 쉽고 분석하기 쉽고 테스트하기 쉽고 최적화하기 쉽기 때문에 권장됩니다.
JacquesB

@JacquesB 이해하기 쉽고, 분석하기 쉽고, 테스트하기 쉽고, 최적화하기 쉬운 이유를 설명하는 좋은 대답이 될 것입니다.
ceving

답변:


72

부작용없이 함수 / 메소드를 작성 하면 순수한 함수 이므로 프로그램의 정확성을 쉽게 추론 할 수 있습니다.

또한 이러한 기능을 쉽게 작성하여 새로운 동작을 만들 수 있습니다.

또한 컴파일러가 함수 결과를 기억하거나 공통 하위 표현식 제거를 사용할 수있는 특정 최적화가 가능합니다.

편집 : Benjol의 요청에 : 많은 상태가 스택에 저장되기 때문에 (Jonas가 여기에서 호출 한 것처럼 제어 흐름이 아닌 데이터 흐름 ), 독립적 인 계산 부분의 실행을 병렬화하거나 달리 재정렬 할 수 있습니다 서로. 한 부품은 다른 부품에 입력을 제공하지 않기 때문에 독립적 인 부품을 쉽게 찾을 수 있습니다.

스택을 롤백하고 컴퓨팅 (예 : 스몰 토크)을 재개 할 수있는 디버거가있는 환경에서 순수한 기능을 사용하면 이전 상태를 검사 할 수 있기 때문에 값이 어떻게 변경되는지 매우 쉽게 확인할 수 있습니다. 돌연변이가 많은 계산에서는 구조 / 알고리즘에 do / undo 작업을 명시 적으로 추가하지 않으면 계산 기록을 볼 수 없습니다. (이것은 첫 번째 단락과 연결됩니다. 순수한 함수를 작성하면 프로그램의 정확성을 쉽게 검사 할 수 있습니다.)


4
답에 동시성에 대해 추가하는 것을 고려해보십시오.
Benjol

5
부작용없는 기능은 테스트 및 재사용이 더 쉽습니다.
LennyProgrammers

@ Lenny222 : 재사용은 함수 구성에 대해 이야기하면서 암시 한 것입니다.
Frank Shearar

@ 프랭크 : 아, 알았어요. :)
LennyProgrammers

@ Lenny222 : 괜찮아; 아마 철자를 쓰는 것이 좋습니다.
Frank Shearar

23

함수형 프로그래밍 에 관한 기사에서 :

실제로 응용 프로그램에는 부작용이 필요합니다. 함수형 프로그래밍 언어 Haskell의 주요 공헌자 인 Simon Peyton-Jones는 다음과 같이 말했습니다. "결국 모든 프로그램은 상태를 조작해야합니다. 상자가 뜨거워진다 " ( http://oscon.blip.tv/file/324976 ) 핵심은 부작용을 제한하고 명확하게 식별하며 코드 전체에 흩어지지 않도록하는 것입니다.



23

기능 프로그래밍은 부작용을 제한하여 프로그램을 이해하고 최적화하기 쉽게 만듭니다. Haskell조차도 파일에 쓸 수 있습니다.

본질적으로 함수형 프로그래머는 부작용이 악하다고 생각하지 않으며 부작용의 사용을 제한하는 것이 좋다고 생각합니다. 나는 그것이 단순한 구별처럼 보일 수 있지만 모든 차이를 만듭니다.


이것이 바로 "금기"와 같은 이유입니다. FPL은 부작용을 제한하도록 권장합니다.
Frank Shearar

접근 방식으로 +1 부작용은 여전히 ​​존재합니다. 실제로, 그들은 제한되어 있습니다
Belun

명확히하기 위해, 나는 왜 함수형 프로그래밍에서 부작용이 허용되지 않는지 또는 부작용이 필요하지 않은 이유를 말하지 않았습니다. 나는 그것이 기능 언어로 허용되고 때로는 필수라는 것을 알고 있습니다. 그러나 함수형 프로그래밍에서는 매우 권장되지 않습니다. 왜? 그게 내 질문이었다.
Gulshan

@Gulshan-부작용으로 인해 프로그램을 이해하고 최적화하기가 어렵습니다.
ChaosPandion

하스켈의 경우, 요점은 "부작용을 제한하지 않는"것입니다. LANGUAGE에서는 부작용을 표현할 수 없습니다. 어떤 기능 readFile을 수행 하는지 는 일련의 동작을 정의하는 것입니다. 이 시퀀스는 기능적으로 순수하며해야 할 일을 설명하는 추상 트리와 비슷합니다. 그런 다음 실제 더티 부작용은 런타임에 의해 수행됩니다.
sara

13

몇 가지 참고 사항 :

  • 부작용이없는 기능은 병렬로 간단하게 실행할 수 있지만 부작용이있는 기능은 일반적으로 일종의 동기화가 필요합니다.

  • 부작용이없는 함수는 정확한 결과를 얻는 한 함수가 실제로 실행 되었는지 여부는 중요하지 않기 때문에보다 적극적인 최적화 (예 : 결과 캐시를 투명하게 사용)를 허용합니다.


매우 흥미로운 점 : 함수가 실제로 실행되었는지 여부는 중요하지 않습니다 . 동등한 매개 변수가 주어지면 부작용이없는 함수에 대한 후속 호출을 제거 할 수있는 컴파일러로 끝나는 것이 흥미로울 것 입니다.
Noel Widmer

1
@NoelWidmer 이와 같은 것이 이미 존재합니다. Oracle의 PL / SQL은 deterministic부작용이없는 함수에 대한 절을 제공 하므로 필요 이상으로 자주 실행되지 않습니다.
user281377

와! 그러나 컴파일러가 명시 적 플래그를 지정하지 않고 자체적으로 알아낼 수 있도록 언어는 의미 론적으로 표현해야한다고 생각합니다 (구문이 무엇인지 확실하지 않습니다). 해결책은 매개 변수를 변경 가능 / 불변으로 지정할 수 있습니다. 일반적으로 말하면 컴파일러가 부작용에 대한 가정을 할 수있는 강력한 유형의 시스템이 필요합니다. 그리고 기능은 원하는 경우 해제 할 수 있도록해야합니다. 옵트 인 대신 옵트 아웃합니다. 나는 당신의 대답을 읽을 수 있기 때문에 그게 :) 내가 가지고있는 제한된 지식을 바탕으로, 그냥 내 생각 이지만요
노엘 년 Widmer

deterministic절은 컴파일러에게 결정적 함수임을 알려주는 키워드 일 뿐이며, finalJava 의 키워드가 컴파일러에게 변수를 변경할 수 없음을 알리는 방법과 비교할 수 있습니다.
user281377

11

나는 주로 현재 기능 코드에서 일하고 있으며, 그 관점에서 맹목적으로 명백해 보입니다. 부작용은 코드를 읽고 이해하려는 프로그래머 에게 정신적 부담을줍니다. 한동안 해방 될 때까지 그 부담을 느끼지 못하고 갑자기 부작용이있는 코드를 다시 읽어야합니다.

이 간단한 예를 고려하십시오.

val foo = 42
// Several lines of code you don't really care about, but that contain a
// lot of function calls that use foo and may or may not change its value
// by side effect.

// Code you are troubleshooting
// What's the expected value of foo here?

함수형 언어에서 나는 그것이foo 여전히 42 라는 것을 알고 있다. 나는 심지어 사이에있는 코드를 보거나, 훨씬 덜 이해하거나, 호출하는 함수의 구현 을 필요조차 없다 .

동시성, 병렬화 및 최적화에 관한 모든 것이 훌륭하지만 컴퓨터 과학자들이 브로셔에 적어 놓은 것입니다. 누가 당신의 변수를 변형시키는 지 궁금하지 않고 매일 매일 연습하는 것이 정말 좋습니다.


6

부작용을 일으키는 것이 불가능한 언어는 거의 없습니다. 완전히 부작용이없는 언어는 매우 제한된 용량을 제외하고는 사용하기가 엄청나게 어렵습니다.

부작용이 왜 악으로 간주됩니까?

프로그램이하는 일을 정확히 추론하고 예상 한 일을한다는 것을 증명하기가 훨씬 더 어렵 기 때문입니다.

매우 높은 수준에서 블랙 박스 테스트만으로 전체 3 계층 웹 사이트를 테스트한다고 상상해보십시오. 물론 규모에 따라 가능합니다. 그러나 분명히 많은 중복이 진행되고 있습니다. 이 경우 이다 버그가 (즉,이 부작용과 관련된) 버그가 진단 및 해결하고, 수정이 테스트 환경에 배포 될 때까지, 당신은 잠재적으로 더 테스트를 위해 전체 시스템을 망가뜨릴 수있다.

혜택

이제 축소하십시오. 부작용이없는 무료 코드를 작성하는 데 상당히 능숙하다면, 기존 코드가 무엇을했는지 추론하는 데 얼마나 더 빠릅니까? 단위 테스트를 얼마나 빨리 작성할 수 있습니까? 어떻게 확신 당신은 어떤 부작용과 코드가 버그가없는 보장 된 것으로, 사용자가이 버그에 대한 노출 제한 할 수 있음을 느낄 것 않았다 가 있습니까?

코드에 부작용이없는 경우 컴파일러에서 수행 할 수있는 추가 최적화가있을 수도 있습니다. 이러한 최적화를 구현하는 것이 훨씬 쉬울 수 있습니다. 부작용이없는 코드에 대한 최적화를 개념화하는 것이 훨씬 더 쉬울 수 있습니다. 즉, 컴파일러 공급 업체는 부작용이있는 코드에서는 불가능한 최적화를 구현할 수 있습니다.

또한 코드에 부작용이없는 경우 동시성을 구현, 자동 생성 및 최적화하는 것이 훨씬 간단합니다. 모든 조각을 임의의 순서로 안전하게 평가할 수 있기 때문입니다. 프로그래머가 고도의 동시 코드를 작성하도록 허용하는 것은 컴퓨터 과학이 해결해야 할 다음의 큰 도전과 무어의 법칙 에 대한 나머지 몇 가지 헤지 중 하나로 널리 알려져 있습니다.


1
Ada는 부작용을 일으키는 것을 매우 어렵게 만듭니다. 그러나 불가능하지는 않지만 자신이 무엇을하는지 분명히 알 수 있습니다.
mouviciel

@ mouviciel : 부작용을 매우 어렵게 만드는 유용한 언어가 적어도 있다고 생각하고 모나드에게 전달하려고합니다.
Merlyn Morgan-Graham

4

부작용은 코드에서 "누수"와 비슷하며 나중에 나 자신이나 의심하지 않는 동료가 처리해야합니다.

함수형 언어는 코드를 문맥에 덜 의존적이고 모듈화하는 방법으로 상태 변수와 가변 데이터를 피합니다. 모듈화는 한 개발자의 작업이 다른 개발자의 작업에 영향을 미치거나 손상시키지 않도록합니다.

팀 규모에 따른 개발 속도의 확장은 오늘날 소프트웨어 개발의 "성배"입니다. 다른 프로그래머와 함께 작업 할 때 모듈성만큼 중요한 것은 거의 없습니다. 가장 간단한 논리적 부작용조차도 공동 작업을 매우 어렵게 만듭니다.


+
1-

1
부작용이 "처리해야 할 누출"인 경우 -1입니다. "부작용"(순수하지 않은 코드) 작성은 사소한 컴퓨터 프로그램 작성의 전체 목적입니다.
메이슨 휠러

이 의견은 6 년 후에 나왔지만 부작용이 있고 부작용이 있습니다. 부작용, I / O를 수행하고 사용자에게 결과 제공해야하기 때문에 등등, 모든 프로그램에 실제로 필요한의 바람직한 종류 든을 코드가 상태를 변경하지만 부작용의 다른 종류 - 없이 좋은 I / O를 수행하는 것과 같은 이유는 나중에 처리해야 할 "누설"입니다. 기본 아이디어는 명령 쿼리 분리입니다 . 값을 반환하는 함수는 부작용이 없어야합니다.
rmunn

4

IMHO, 이것은 매우 위선적입니다. 부작용을 좋아하는 사람은 없지만 모두가 필요합니다.

부작용에 대해 너무 위험한 것은 함수를 호출하면 다음에 호출 할 때 함수가 작동하는 방식뿐만 아니라 다른 함수에도 영향을 줄 수 있다는 것입니다. 따라서 부작용은 예측할 수없는 행동과 사소한 의존성을 유발합니다.

OO 및 기능적 프로그래밍 패러다임 모두이 문제를 해결합니다. OO는 우려를 분리하여 문제를 줄입니다. 이는 많은 변경 가능한 데이터로 구성된 응용 프로그램 상태가 객체로 캡슐화되어 있으며 각 상태는 자체 상태 만 유지 관리하는 것을 의미합니다. 이렇게하면 종속성의 위험이 줄어들고 문제가 훨씬 더 격리되고 추적하기가 더 쉽습니다.

함수형 프로그래밍은 훨씬 더 급진적 인 접근 방식을 취하는데, 여기서 애플리케이션 상태는 프로그래머의 관점에서 간단히 변경할 수 없습니다. 이것은 좋은 생각이지만 언어 자체를 쓸모 없게 만듭니다. 왜? 모든 I / O 작업에 부작용이 있기 때문입니다. 입력 스트림에서 읽 자마자 다음에 동일한 기능을 호출하면 결과가 다를 수 있으므로 애플리케이션 상태가 변경 될 수 있습니다. 다른 데이터를 읽거나 작업이 실패 할 수 있습니다. 출력에서도 마찬가지입니다. 출력조차도 부작용이있는 작업입니다. 요즘은 자주 알지 못하지만 출력에는 20K 만 있고 더 이상 출력하면 디스크 공간이 부족하여 앱이 충돌한다고 상상해보십시오.

그렇습니다. 부작용은 프로그래머의 관점에서 불쾌하고 위험합니다. 대부분의 버그는 응용 프로그램 상태의 특정 부분이 고려되지 않고 종종 불필요한 부작용을 통해 거의 모호한 방식으로 연동되는 방식에서 발생합니다. 사용자 관점에서 부작용은 컴퓨터 사용의 핵심입니다. 그들은 내부에서 일어나는 일이나 그것이 조직되는 방식에 신경 쓰지 않습니다. 그들은 무언가를하고 컴퓨터가 그에 따라 변경 될 것으로 기대합니다.


흥미롭게도 로직 프로그래밍은 기능적 부작용을 가질뿐만 아니라; 그러나 일단 할당 된 변수의 값을 변경할 수도 없습니다.
Ilan

@Ilan : 일부 기능 언어에도 적용되며 채택하기 쉬운 스타일입니다.
back2dos

"기능 프로그래밍은 훨씬 더 근본적인 접근 방식을 취하는데, 이는 프로그래머의 관점에서 응용 프로그램 상태를 단순히 변경할 수 없습니다. 이는 좋은 생각이지만 언어 자체를 쓸모 없게 만듭니다. 이유는 무엇입니까? 영향 ": FP는 부작용을 금지하지 않으며, 필요하지 않은 경우 부작용을 제한합니다. 예를 들어 (1) I / O-> 부작용이 필요합니다. (2) 일련의 값-> 부작용 (예 : 누산기 변수가있는 루프의 경우)에서 집계 함수를 계산할 필요가 없습니다.
Giorgio

2

부작용은 테스트 할 때 고려해야 할 추가 입 / 출력 파라미터를 도입합니다.

이것은 환경이 검증되는 코드에만 국한 될 수 없기 때문에 코드 검증이 훨씬 더 복잡해 지지만 주변 환경의 일부 또는 전부를 가져와야합니다. 전체 Java EE 서버 내부에 의존하는 코드 ....)

부작용을 피하려고하면 코드를 실행하는 데 필요한 외부 처리량을 제한 할 수 있습니다.


1

내 경험상 Object Orientated 프로그래밍의 좋은 디자인은 부작용이있는 기능을 사용해야합니다.

예를 들어 기본 UI 데스크톱 응용 프로그램을 사용하십시오. 프로그램의 도메인 모델의 현재 상태를 나타내는 객체 그래프가 힙에있는 실행중인 프로그램이있을 수 있습니다. 메시지는 해당 그래프의 개체에 도착합니다 (예 : UI 계층 컨트롤러에서 호출 된 메서드 호출을 통해). 힙의 오브젝트 그래프 (도메인 모델)는 메시지에 대한 응답으로 수정됩니다. 모델의 관찰자에게는 변경 사항, UI 및 기타 리소스가 수정되었음을 알립니다.

이러한 힙 수정 및 화면 수정 부작용의 올바른 배열은 악의가 아니라는 점에서 OO 디자인의 핵심입니다 (이 경우 MVC 패턴).

물론, 이것이 당신의 방법이 임의의 부작용을 가져야한다는 것을 의미하지는 않습니다. 또한 부작용이없는 함수는 코드의 가독성 및 때로는 성능을 향상시키는 데 도움이됩니다.


1
관찰자 (UI 포함)는 객체가 보내는 메시지 / 이벤트를 구독하여 수정에 대해 알아 내야합니다. 객체 가 관찰자를 직접 수정 하지 않는 한 부작용은 아닙니다. 이것은 나쁜 디자인입니다.
ChrisF

1
@ChrisF 가장 확실하게 부작용입니다. 관찰자에게 전달 된 메시지 (OO 언어에서 인터페이스의 메소드 호출 일 가능성이 높음)는 힙 변경시 UI 구성 요소의 상태를 초래합니다 (이 힙 오브젝트는 프로그램의 다른 부분에서 볼 수 있음). UI 구성 요소는 메소드의 매개 변수 또는 리턴 값이 아닙니다. 공식적인 의미에서, 기능이 부작용이 없도록하려면 dem 등원이어야합니다. 예를 들어 MVC 패턴의 알림은 UI가 수신 한 메시지 목록 (콘솔)을 두 번 호출하면 다른 프로그램 상태를 표시 할 수 있습니다.
flamingpenguin

0

악은 약간 위에있다. 그것은 모두 언어의 사용 상황에 달려있다.

이미 언급 한 사람들에 대한 또 다른 고려 사항은 기능적 부작용이 없다면 프로그램의 정확성을 증명하는 것이 훨씬 간단하다는 것입니다.


0

위의 질문에서 지적했듯이 기능적 언어는 코드가 부작용을 일으키는 것을 막지 못하므로 주어진 코드에서 언제 어떤 부작용이 발생할 수 있는지 관리하는 도구를 제공합니다.

이것은 매우 흥미로운 결과를 초래합니다. 첫째, 가장 명백하게, 이미 설명한 부작용 무료 코드로 할 수있는 많은 일이 있습니다. 그러나 부작용이있는 코드로 작업 할 때도 할 수있는 다른 작업이 있습니다.

  • 변경 가능한 상태의 코드에서는 지정된 함수 외부에서 누출되지 않도록 정적으로 확인하는 방식으로 상태 범위를 관리 할 수 ​​있으므로 참조 계산 또는 마크 앤 스윕 스타일 체계없이 가비지를 수집 할 수 있습니다. 그래도 참조가 남아 있지 않아야합니다. 개인 정보에 민감한 정보 등을 유지하는데도 동일한 보증이 유용합니다. (이는 haskell의 ST 모나드를 사용하여 달성 할 수 있습니다)
  • 여러 스레드에서 공유 상태를 수정할 때 트랜잭션 끝에서 변경 사항을 추적하고 원자 업데이트를 수행하거나 다른 스레드가 충돌하는 수정을 수행 한 경우 트랜잭션을 롤백하고 반복하여 잠금이 필요하지 않습니다. 이것은 코드가 상태 수정 (행복하게 버릴 수있는 것) 이외의 다른 효과가 없도록 보장 할 수 있기 때문에 달성 할 수 있습니다. 이는 Haskell의 STM (Software Transactional Memory) 모나드에 의해 수행됩니다.
  • 우리는 코드의 효과를 추적하고 사소하게 샌드 박스를 만들 수 있습니다. 안전을 위해 수행해야 할 모든 효과를 필터링 하여 웹 사이트에서 사용자 입력 코드를 안전하게 실행할 수 있습니다.

0

복잡한 코드 기반에서 부작용의 복잡한 상호 작용은 내가 생각하기에 가장 어려운 것입니다. 뇌가 작동하는 방식만으로 개인적으로 만 말할 수 있습니다. 부작용과 지속적인 상태 및 입력 변경 등을 통해 각 개별 기능에서 "무엇"이 발생 하는가가 아니라 "언제"와 "어디에"가 올바른지에 대해 추론해야합니다.

나는 "무엇"에 집중할 수 없습니다. 호출자가 코드를 사용하여 코드 전체에 신뢰성의 공기를 퍼뜨릴 수있는 부작용을 일으키는 함수를 철저히 테스트 한 후에는 호출자가 여전히 잘못된 스레드에서 잘못된 스레드에서 호출하여 잘못 사용할 수 있기 때문에 결론을 내릴 수 없습니다. 주문. 한편 부작용을 일으키지 않고 (입력을 건드리지 않고) 입력이 주어지면 새로운 출력을 반환하는 함수는 이런 식으로 오용하는 것이 거의 불가능합니다.

그러나 나는 실용 주의적이거나 최소한 노력하려고 노력하고 있으며 코드의 정확성에 대해 추론하기 위해 모든 부작용을 최소한으로 표시해야한다고 생각하지는 않습니다 (최소한) C)와 같은 언어에서는이 작업을 수행하기가 매우 어렵습니다. 정확성에 대해 추론하기가 매우 어려운 곳은 복잡한 제어 흐름과 부작용이 결합 된 경우입니다.

복잡한 제어 흐름은 본질적으로 그래프와 같으며 종종 재귀 적 또는 재귀 적입니다 (예 : 이벤트를 재귀 적으로 직접 호출하지는 않지만 실제로는 "재귀 적"인 이벤트 큐), 아마도 할 일 실제 연결된 그래프 구조를 순회하는 과정 또는 코드베이스의 모든 종류의 다른 부분으로 이어지고 다른 부작용을 유발하는 처리를 위해 다양한 이벤트가 포함 된 비 균일 이벤트 큐를 처리하는 과정에서 발생합니다. 코드에서 궁극적으로 끝나는 모든 장소를 찾으려고하면 복잡한 그래프와 유사하며 잠재적으로 그 순간에 거기에 없었을 것으로 예상되는 그래프의 노드와 잠재적으로 같고 부작용을 일으키고

함수형 언어는 매우 복잡하고 재귀적인 제어 흐름을 가질 수 있지만 프로세스에서 발생하는 모든 종류의 절충 적 부작용이 없기 때문에 결과는 정확성 측면에서 이해하기 쉽습니다. 복잡한 제어 흐름이 절충주의 부작용을 만났을 때만 일어나고있는 일의 전체와 항상 올바른 일을 할 것인지 이해하는 것이 두통을 유발합니다.

따라서 이러한 경우가있을 때, 불가능하지는 않더라도 그러한 코드의 정확성에 대해 매우 확신하는 것은 매우 어려운 일입니다. 예상치 못한 일이 발생하지 않고 그러한 코드를 변경할 수 있다는 확신은 없습니다. 따라서 나에게 해결책은 제어 흐름을 단순화하거나 부작용을 최소화 / 통합하는 것입니다 (통합함으로써 시스템의 특정 단계에서 두 가지 또는 세 가지가 아닌 한 가지 유형의 부작용 만 발생하는 것을 의미합니다) 다스). Simpleton 두뇌가 존재하는 코드의 정확성과 내가 도입 한 변경의 정확성에 대해 자신감을 갖도록하려면 두 가지 중 하나가 필요합니다. 부작용이 제어 흐름과 함께 균일하고 단순하면 부작용을 유발하는 코드의 정확성에 대해 확신하기가 매우 쉽습니다.

for each pixel in an image:
    make it red

이러한 코드의 정확성에 대해 추론하기는 쉽지만 주로 부작용이 너무 균일하고 제어 흐름이 너무 간단하기 때문입니다. 그러나 다음과 같은 코드가 있다고 가정 해 봅시다.

for each vertex to remove in a mesh:
     start removing vertex from connected edges():
         start removing connected edges from connected faces():
             rebuild connected faces excluding edges to remove():
                  if face has less than 3 edges:
                       remove face
             remove edge
         remove vertex

그런 다음 이것은 엄청나게 지나치게 단순화 된 의사 코드이며 일반적으로 훨씬 더 많은 함수와 중첩 루프 및 계속해야 할 훨씬 더 많은 것들 (여러 텍스처 맵, 뼈 가중치, 선택 상태 등 업데이트)이 포함되지만 의사 코드조차도 너무 어렵습니다. 복잡한 그래프와 같은 제어 흐름과 부작용의 상호 작용으로 인해 정확성에 대한 이유. 따라서 단순화를위한 한 가지 전략은 처리를 연기하고 한 번에 한 가지 유형의 부작용에만 집중하는 것입니다.

for each vertex to remove:
     mark connected edges
for each marked edge:
     mark connected faces
for each marked face:
     remove marked edges from face
     if num_edges < 3:
          remove face

for each marked edge:
     remove edge
for each vertex to remove:
     remove vertex

... 단순화의 반복으로이 효과에 무언가. 즉, 계산 비용이 많이 발생하는 데이터를 여러 번 통과한다는 것을 의미하지만 부작용과 제어 흐름이 균일하고 단순한 특성으로 인해 이러한 결과 코드를 더 쉽게 멀티 스레드 할 수있는 경우가 많습니다. 또한 각 루프는 연결된 그래프를 통과하고 부작용을 일으키는 것보다 캐시 친화적으로 만들 수 있습니다 (예 : 병렬 비트 세트를 사용하여 통과해야 할 항목을 표시하여 지연 된 패스를 정렬 된 순서대로 정렬 할 수 있습니다 비트 마스크 및 FFS 사용). 그러나 가장 중요한 것은 두 번째 버전이 버그를 유발하지 않고 변경뿐만 아니라 정확성 측면에서 추론하기가 훨씬 쉽다는 것입니다. 그래서'

그리고 결국, 우리는 어느 시점에서 부작용이 발생해야합니다. 그렇지 않으면 아무 데나 데이터를 출력하는 함수 만있을뿐입니다. 종종 우리는 파일에 무언가를 기록하고, 스크린에 무언가를 표시하고, 소켓을 통해 데이터를 보내야합니다. 그러나 우리는 계속되는 부작용의 수를 확실히 줄이고 제어 흐름이 매우 복잡 할 때 발생하는 부작용의 수를 줄일 수 있으며, 우리가한다면 버그를 피하는 것이 훨씬 쉽다고 생각합니다.


-1

악이 아닙니다. 제 생각에는 부작용이 있거나없는 두 가지 기능 유형을 구별해야합니다. 부작용이없는 함수 :-항상 동일한 인수를 사용하여 동일한 값을 반환하므로 인수가없는 함수는 의미가 없습니다. 즉, 이러한 기능의 순서는 아무런 역할을하지 않습니다. 즉, 다른 코드없이 실행할 수 있어야하며 단독으로 디버깅 할 수 있어야합니다 (!). 그리고 지금, lol, JUnit이 무엇을하는지보세요. 부작용이있는 기능 :-일종의 "누출", 자동으로 강조 할 수있는 것-실수 디버깅 및 검색, 일반적으로 부작용으로 인해 발생하는 것이 매우 중요합니다. -부작용이있는 모든 기능에는 부작용이없는 자체 "부분"이 있으며 자동으로 분리 할 수도 있습니다. 부작용은 너무나 사악합니다.


이것은 이전의 12 가지 답변에서 언급되고 설명 된 포인트를 넘어서는 실질적인 것을 제공하지 않는 것 같습니다
gnat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.