6.6. 요약
6.6.1. 모나드 결합하기
모나드를 처음부터 작성할 때는 각 효과가 모나드에 추가되는 방식을 설명하는 경향이 있는 디자인 패턴들이 있습니다. 리더(reader) 효과는 모나드의 타입을 리더의 환경으로부터의 함수로 만듦으로써 추가되고, 상태 효과는 초기 상태로부터 최종 상태와 짝지어진 값으로 가는 함수를 포함시킴으로써 추가되며, 실패나 예외는 반환 타입에 합 타입(sum type)을 포함시킴으로써 추가되고, 로깅이나 그 밖의 출력은 반환 타입에 곱 타입(product type)을 포함시킴으로써 추가됩니다. 기존 모나드도 반환 타입의 일부로 만들 수 있으며, 이를 통해 그 효과를 새로운 모나드에 포함시킬 수 있습니다.
이러한 설계 패턴은 어떤 기저 모나드에 효과를 추가하는 모나드 트랜스포머를 정의함으로써 재사용 가능한 소프트웨어 컴포넌트 라이브러리로 만들어집니다. 모나드 트랜스포머는 더 단순한 모나드 타입들을 인자로 받아, 강화된 모나드 타입을 반환합니다. 최소한, 모나드 트랜스포머는 다음 인스턴스들을 제공해야 합니다:
모나드 트랜스포머는 다형적 구조체나 귀납적 타입으로 구현될 수도 있지만, 대개는 기저 모나드 타입에서 확장된 모나드 타입으로의 함수로 구현됩니다.
6.6.2. 효과를 위한 타입 클래스
흔히 사용되는 설계 패턴은 특정 효과를 갖는 모나드, 그 효과를 다른 모나드에 추가하는 모나드 트랜스포머, 그리고 그 효과에 대한 일반적인 인터페이스를 제공하는 타입 클래스를 정의함으로써 해당 효과를 구현하는 것입니다. 이를 통해 프로그램이 자신에게 필요한 효과가 무엇인지만 명시하도록 작성할 수 있으며, 따라서 호출자는 적절한 효과를 갖춘 모나드라면 무엇이든 제공할 수 있습니다.
때로는 (예를 들어 상태를 제공하는 모나드에서 상태의 타입이나, 예외를 제공하는 모나드에서 예외의 타입과 같은) 보조 타입 정보가 출력 매개변수인 경우가 있고, 때로는 그렇지 않은 경우도 있습니다. 출력 파라미터는 각 종류의 효과를 한 번씩만 사용하는 단순한 프로그램에서 가장 유용하지만, 주어진 프로그램에서 동일한 효과의 인스턴스가 여러 번 사용될 경우 타입 검사기가 너무 일찍 잘못된 타입으로 확정해 버릴 위험이 있습니다. 따라서 일반적으로 두 버전이 모두 제공되며, 타입 클래스의 일반 매개변수 버전은 이름이 -Of로 끝납니다.
6.6.3. 모나드 트랜스포머는 교환되지 않습니다
모나드에서 트랜스포머의 순서를 바꾸면 그 모나드를 사용하는 프로그램의 의미가 달라질 수 있다는 점에 유의하는 것이 중요합니다. 예를 들어, StateT와 ExceptT의 순서를 바꾸면 예외가 발생했을 때 상태 변경 사항을 잃어버리는 프로그램이 되거나, 변경 사항을 유지하는 프로그램이 될 수 있습니다. 대부분의 명령형 언어는 후자만을 제공하지만, 모나드 트랜스포머가 제공하는 증가된 유연성은 당면한 작업에 알맞은 종류를 선택하기 위한 고민과 주의를 요구합니다.
6.6.4. 모나드 트랜스포머를 위한 do-표기법
Lean의 do-블록은 어떤 값으로 블록을 종료하는 조기 반환, 지역적으로 가변인 변수, break와 continue를 사용하는 for-루프, 그리고 단일 분기 if-문을 지원합니다. 이는 증명 작성을 위해 Lean을 사용하는 데 방해가 되는 명령형 기능을 도입하는 것처럼 보일 수 있지만, 실제로는 모나드 트랜스포머의 특정한 흔한 용례를 위한 더 편리한 구문에 지나지 않습니다. 내부적으로, do-블록이 작성된 모나드가 무엇이든 간에 이러한 추가 효과를 지원하기 위해 ExceptT와 StateT를 적절히 사용하여 변환됩니다.