태그 보관물: functional-programming

functional-programming

아마도 모나드 대 예외 비해 Maybe 모나드 의 장점이 무엇인지

예외에 비해 Maybe 모나드 의 장점이 무엇인지 궁금합니다 . 그것은 Maybe명시적이고 (공간을 많이 차지하는) try..catch구문 방식 처럼 보입니다 .

업데이트 의도적으로 Haskell을 언급 하지 않습니다 .



답변

사용 Maybe(또는 사촌 Either기본적으로 동일한 방식으로 작동하지만 대신에 임의의 값을 반환 할 수 있습니다 Nothing) 예외 약간 다른 용도로 사용됩니다. Java 용어로는 런타임 예외가 아닌 확인 된 예외가있는 것과 같습니다. 예상치 못한 오류가 아니라 처리해야 할 것으로 예상 되는 것을 나타냅니다 .

따라서 항목이 목록에 없을 가능성이 있기 때문에 같은 함수 indexOfMaybe값을 반환 합니다. 이것은 null유형 안전 방식을 사용하여 null케이스 를 처리해야한다는 점을 제외하고 함수에서 돌아 오는 것과 매우 유사 합니다 . Either오류 사례와 관련된 정보를 반환 할 수 있다는 점을 제외하고는 동일한 방식으로 작동하므로 실제로는 예외와 비슷합니다 Maybe.

그렇다면 Maybe/ Either접근법 의 장점은 무엇 입니까? 하나, 그것은 언어의 일류 시민입니다. Either예외를 던지는 것과 사용하는 함수를 비교해 봅시다 . 예외적 인 경우, 유일한 유일한 의지는 try...catch진술입니다. 이 Either기능을 위해 기존 조합기를 사용하여 흐름 제어를보다 명확하게 만들 수 있습니다. 다음은 몇 가지 예입니다.

먼저, 그렇지 않은 함수를 얻을 때까지 행에서 오류가 발생할 수있는 여러 함수를 시도한다고 가정 해 봅시다. 오류가 없으면 특별한 오류 메시지를 반환하려고합니다. 이것은 실제로 매우 유용한 패턴이지만를 사용하는 것은 끔찍한 고통 try...catch입니다. 행복하게도, Either단지 정상적인 값이므로 기존 함수를 사용하여 코드를 훨씬 명확하게 만들 수 있습니다.

firstThing <|> secondThing <|> throwError (SomeError "error message")

또 다른 예는 옵션 기능입니다. 쿼리를 최적화하는 기능을 포함하여 실행할 여러 기능이 있다고 가정 해 봅시다. 이것이 실패하면 다른 모든 것을 실행하기를 원합니다. 다음과 같은 코드를 작성할 수 있습니다.

do a <- getA
   b <- getB
   optional (optimize query)
   execute query a b

이 두 가지 경우 모두를 사용하는 것보다 명확하고 짧으며 try..catch더 중요하게 더 의미 론적입니다. 같은 기능을 사용 <|>하거나하는 것은 optional당신의 의도가 수 많이 사용하는 것보다 명확 try...catch항상 예외를 처리 할 수 있습니다.

또한 ! 와 같은 줄로 코드를 정리할 필요는 없습니다if a == Nothing then Nothing else ... . 치료 MaybeEither모나드의 요점은 이것을 피하는 것입니다. 전파 의미론을 바인드 함수로 인코딩하여 널 / 오류 검사를 무료로 얻을 수 있습니다. 명시 적으로 확인 해야하는 유일한 시간은 Nothing주어진 이외의 것을 반환하고 싶을 때뿐입니다. Nothing심지어 코드를 더 좋게 만드는 표준 라이브러리 함수가 많이 있습니다.

마지막으로, 또 다른 장점은 Maybe/ Either유형이 더 간단 하다는 것입니다 . 추가 키워드 또는 제어 구조를 사용하여 언어를 확장 할 필요는 없습니다. 모든 것이 단지 라이브러리 일뿐입니다. 그것들은 단지 정상적인 값이기 때문에 타입 시스템을 더 단순하게 만듭니다 .Java에서는 타입 (예 : 반환 타입)과 throws사용하지 않을 효과 (예 : 명령문) 를 구별해야합니다 Maybe. 또한 다른 사용자 정의 유형과 동일하게 작동하므로 언어에 특수한 오류 처리 코드가 없어도됩니다.

또 다른 승리 즉 Maybe/ Either펑터와 모나드는, 그들은 일반적으로 기존의 모나드 제어 흐름 기능 (있는 공정한 번호가)와, 활용할 수있는 수단, 다른 모나드와 함께 잘 재생합니다.

즉, 몇 가지주의 사항이 있습니다. 우선, 점검되지 않은 예외를 대체 Maybe하거나 Either대체 하지 마십시오 . 0으로 나누는 것과 같은 것을 처리하는 다른 방법이 필요할 때마다 모든 단일 부서가 Maybe값을 반환하는 것이 고통 스럽기 때문에 간단 합니다.

또 다른 문제는 여러 유형의 오류가 반환되는 것입니다 (이 경우에만 적용됨 Either). 예외를 사용하면 동일한 함수에서 다른 유형의 예외를 처리 할 수 ​​있습니다. 를 사용 Either하면 한 가지 유형 만 얻을 수 있습니다. 이는 하위 유형을 지정하거나 생성자로서 모든 다른 유형의 오류를 포함하는 ADT를 통해 극복 할 수 있습니다 (이 두 번째 방법은 Haskell에서 일반적으로 사용되는 방법 임).

아직도, 나는 더 간단하고 유연하기 때문에 Maybe/ Either접근법을 선호합니다 .


답변

  1. 예외는 문제의 원인에 대한 자세한 정보를 전달할 수 있습니다. OpenFile()던질 수 FileNotFound또는 NoPermission또는 TooManyDescriptors등 없음이 정보를 전달하지 않습니다.
  2. 반환 값이없는 상황에서는 예외를 사용할 수 있습니다 (예 : 언어가있는 언어의 생성자 사용).
  3. 예외를 사용하면 많은 if None return None스타일 문 없이 정보를 스택에 쉽게 보낼 수 있습니다 .
  4. 예외 처리는 거의 항상 값을 반환하는 것보다 더 높은 성능 영향을 미칩니다.
  5. 가장 중요한 것은 예외와 어쩌면 모나드는 다른 목적을 가지고 있다는 것입니다. 예외는 문제를 나타내는 데 사용되지만 어쩌면 그렇지 않습니다.

    “간호사, 5 호실에 환자가 있다면 기다릴 수 있습니까?”

    • 아마 모나드 : “의사, 5 호실에는 환자가 없습니다.”
    • 예외 : “의사, 5 호실은 없습니다!”

    ( “if”에 유의 하십시오-의사가 아마도 모나드를 기대하고 있음을 의미합니다 )


답변

“아마도”는 예외를 대체하지 않습니다. 예외는 예외적 인 경우에 사용하기위한 것입니다 (예 : DB 연결을 열고 DB 서버는 존재하지 않지만). “아마도”는 유효한 값이 있거나 없을 수있는 상황을 모델링하기위한 것입니다. 키에 대한 사전에서 값을 얻는다고 가정하십시오. 키가 있거나 없을 수 있습니다. 이러한 결과에 대해 “예외적 인”것은 없습니다.


답변

나는 Tikhon의 대답을 두 번째로 생각하지만 모든 사람들이 놓친 매우 중요한 실질적인 포인트가 있다고 생각합니다.

  1. 적어도 주류 언어로 된 예외 처리 메커니즘은 개별 스레드에 밀접하게 연결되어 있습니다.
  2. Either메커니즘은 스레드에 전혀 연결되지 않습니다.

오늘날 우리가 실제로보고있는 것은 많은 비동기식 프로그래밍 솔루션이 다양한 Either스타일의 오류 처리 방식을 채택하고 있다는 것입니다. 다음 링크 중 하나에 자세히 설명 된 Javascript promise를 고려하십시오 .

약속 개념을 사용하면 다음과 같은 비동기 코드를 작성할 수 있습니다 (마지막 링크에서 가져옴).

var greetingPromise = sayHello();
greetingPromise
    .then(addExclamation)
    .then(function (greeting) {
        console.log(greeting);    // 'hello world!!!!’
    }, function(error) {
        console.error('uh oh: ', error);   // 'uh oh: something bad happened’
    });

기본적으로 약속은 다음과 같은 객체입니다.

  1. 아직 완료되었거나 완료되지 않은 비동기 계산의 결과를 나타냅니다.
  2. 결과에 대해 수행 할 추가 작업을 연결하여 결과를 사용할 수있을 때 트리거되며 결과를 약속으로 사용할 수 있습니다.
  3. 약속의 계산이 실패 할 경우 호출되는 실패 처리기를 연결할 수 있습니다. 핸들러가 없으면 오류가 체인의 이후 핸들러로 전파됩니다.

기본적으로 계산이 여러 스레드에서 발생할 때 언어의 기본 예외 지원이 작동하지 않기 때문에 약속 구현은 오류 처리 메커니즘을 제공해야하며 이는 Haskell의 Maybe/ Either유형 과 유사한 모나드로 판명됩니다 .


답변

Haskell 타입 시스템은 사용자에게의 가능성을 인정해야 Nothing하지만, 프로그래밍 언어는 종종 예외가 발생하지 않아도됩니다. 즉, 컴파일 타임에 사용자가 오류를 확인했음을 알 수 있습니다.


답변

아마도 모나드는 기본적으로 대부분의 주류 언어에서 “널 의미 오류”확인 (널을 확인해야하는 경우 제외)과 동일하며 거의 동일한 장점과 단점이 있습니다.


답변

예외 처리는 팩토링 및 테스트에 큰 고통이 될 수 있습니다. 나는 파이썬이 엄격한 “try … catch”블록없이 예외를 잡을 수있는 멋진 “with”구문을 제공한다는 것을 알고있다. 그러나 Java에서 예를 들어, catch catch 블록은 크고, 상용구이거나, 장황하거나 매우 장황하며 분해하기가 어렵습니다. 또한 Java는 확인 된 예외와 확인되지 않은 예외에 대한 모든 노이즈를 추가합니다.

대신 모나드가 예외를 잡아서 처리 이상이 아닌 모나드 공간의 속성으로 취급하면 던지거나 잡는 것에 관계없이 해당 공간에 바인딩하는 함수를 자유롭게 혼합하고 일치시킬 수 있습니다.

그래도 모나드가 예외가 발생할 수있는 상황 (예 : null 체크를 Maybe로 밀어 넣기)을 방지하면 더 좋습니다. 만약 … 그런 다음 시도하는 것보다 훨씬, 팩터링하고 테스트하기가 훨씬 쉽습니다.

내가 본 것에서 Go는 각 함수가 반환 (응답, 오류)하도록 지정하여 비슷한 접근 방식을 취하고 있습니다. 이는 핵심 응답 유형이 오류 표시로 장식 된 모나드 공간으로 함수를 “리프팅”하는 것과 같으며, 예외적으로 던지기 및 잡기 예외를 효과적으로 처리합니다.