어떻게 행동해야하는지 추상을 고려하십시오. 프로그램이 프로그램은 기능의 나머지 부분을 삭제하고 오류 메시지를 반환하는 경우에는 기능
실패의 나머지 부분을 실행하는 경우
- 성공 : 조건을 선택하면 두 가지 결과 중 하나가 있습니다.
여러 조건을 검사하는 것은 재귀 적으로 볼 수 있습니다. "함수의 나머지 부분"을 실행할 때마다 결과를 반환하는 마지막 단계에 도달 할 때까지 다음 조건을 찾습니다. 이제 문제를 해결하기위한 첫 걸음으로, 그 구조를 사용하여 일들을 나누어 보겠습니다. 기본적으로, 우리는 여러 조건을 여러 조건부 함수로 구성 할 수있는 조각으로 바꾸기를 원합니다. 우리는이 조각들의 본질에 대해 무엇을 결론 지을 수 있습니까?
1) 각 조각은 두 가지 유형 중 하나를 반환 할 수 있습니다. 오류 메시지 또는 다음 단계의 결과.
2) 각 조각은 다음 단계를 실행할지 여부를 결정해야하므로 단계를 결합 할 때 다음 단계를 나타내는 함수를 인수로 제공해야합니다.
3) 각 조각에는 다음 단계가 주어지기 때문에 균일 한 구조를 유지하려면 최종 무조건 단계를 조건부 단계와 동일한 것으로 변환해야합니다.
첫 번째 요구 사항은 Google 검색 결과에 Either String a
과 같은 유형이 필요하다는 것을 분명히 암시합니다. 이제 두 번째 요구 사항에 맞는 결합 함수와 세 번째 요구 사항에 맞는 래핑 함수가 필요합니다. 또한 단계를 결합 할 때 이전 단계의 데이터에 액세스 할 수 있습니다 (예 : 서로 다른 두 입력의 유효성을 검사 한 다음 두 입력이 같은지 확인). 각 단계에서 이전 단계의 결과를 인수로 가져와야합니다.
각 단계 유형을 약어로 표기하면 다른 기능에는 어떤 유형이 있습니까?
이제 형식 서명이 이상하게 보입니다. 그렇지 않습니까?
"오류 메시지와 함께 일찍 실패 할 수있는 계산을 실행하는"일반적인 전략은 실제로 모나드 구현에 적합합니다. 실제로 mtl package에는 이미 하나가 있습니다. 더 중요한 것은이 경우에 모나드 이 있습니다. 즉, 오류 모나드 구조를 다른 모나드에 추가 할 수 있습니다 (예 : IO
).
그래서, 우리가 모듈을 가져 따뜻한 퍼지 ErrorT
에 IO
을 마무리하는 타입의 동의어를 만들고, 멀리 갈 수 :
import Control.Monad.Error
type EIO a = ErrorT String IO a
assert pred err = if pred then return() else throwError err
askUser prompt = do
liftIO $ putStr prompt
liftIO getLine
main :: IO (Either String())
main = runErrorT test
test :: EIO()
test = do
x1 <- askUser "Please enter anything but the number 5: "
assert (x1 /= "5") "Entered 5"
x2 <- askUser "Please enter a capital letter Z: "
assert (x2 == "Z") "Didn't enter Z"
x3 <- askUser "Please enter the same thing you entered for the first question: "
assert (x3 == x1) $ "Didn't enter " ++ x1
return() -- superfluous, here to make the final result more explicit
당신이 기대하는 것처럼, test
을 실행 한 결과, 성공의 경우 Right()
이거나 실패한 경우 Left String
입니다. 여기서 String
은 적절한 메시지입니다. assert
이 실패를 리턴하면 다음 조치 중 하나도 수행되지 않습니다.
IO
작업의 결과를 테스트하는 경우 과 유사한 도우미 함수를 쓰는 것이 가장 쉽습니다.이 방법은 대신 IO Bool
또는 다른 방법을 사용합니다.
또한 liftIO
의 사용이 EIO
의 값으로 IO
작업을 변환하고, runErrorT
는 EIO
조치를 실행하고 전체 결과와 Either String a
값을 반환 할 수 있습니다. 더 자세한 정보가 필요하면 monad transformers을 읽어보십시오.
아주 좋은 대답입니다! –
오류 모나드를 좋아합니다! 또한 컴파일러에서 가짜 오류 메시지를 스켈링하기에 좋습니다 .... +1 –
@Norman Ramsey : 그렇습니다! 하스켈과의 초기 모험에서 '오류'로 '어느 쪽이든'을 사용하는 도서관을 만났을 때 나는 가치를 전달하기 위해 '권리'에서 추출하는 것이 헛되지 않았다. 그래서 (hightsight에서)'fmap'과'(>> =)'와 거의 같은 함수를 작성했습니다. 같은 시간에 모나드 구조를 인식하는 이해를 얻었을 때, 나는 MonadError가 항상 존재한다는 것을 발견했고, 나의 원유 재발 명에 대해 다소 어리 석다는 것을 알게되었다."공상적인"모나드를 둘러싼 모든 소동에서 모나드 '우아함'과 '어쩌면'이 잊혀 질 것 같습니다 ... –