모나드(기능 프로그래밍)
Monad (functional programming)함수형 프로그래밍에서 모나드는 프로그램 단편(함수)을 결합하고 그 반환값을 추가 연산을 통해 유형으로 감싸는 구조를 가진 소프트웨어 설계 패턴이다.래핑 모나드유형의 정의와 더불어 모나드유형의 값을 래핑하는 연산자와 모나드유형의 값을 출력하는 함수를 조합하는 연산자(이것을 모나드함수라고 부릅니다)의 2개의 연산자를 정의합니다.범용 언어에서는 모나드를 사용하여 공통 작업에 필요한 보일러 플레이트 코드를 줄입니다(정의되지 않은 값 또는 오류 가능성이 있는 함수 처리, 부기 코드 캡슐화 등).기능 언어는 복잡한 함수 시퀀스를 제어 흐름과 [1][2]부작용을 추상화하는 간결한 파이프라인으로 바꾸기 위해 모나드를 사용합니다.
모나드의 개념과 용어는 모두 원래 범주 이론에서 비롯되었으며, 여기서 모나드는 추가 [a]구조를 가진 함수로 정의됩니다.1980년대 후반과 1990년대 초에 시작된 연구는 모나드가 외관상 이질적인 컴퓨터 과학 문제를 통일된 기능 모델 하에서 가져올 수 있다는 것을 밝혀냈습니다.카테고리 이론은 또한 모나드 법칙으로 알려진 몇 가지 공식 요건을 제공하며, 모나드 법칙은 모나드에 의해 충족되어야 하며 모나드 [3][4]코드를 검증하는 데 사용될 수 있습니다.
모나드는 일종의 계산을 위해 의미를 명확하게 하기 때문에 편리한 언어 기능을 구현하기 위해 사용될 수도 있습니다.Haskell과 같은 일부 언어에서는 일반적인 모나드 구조와 공통 인스턴스에 [1][5]대해 핵심 라이브러리에 사전 구축된 정의를 제공합니다.
개요
"모나드에게"m
, type 값m a
유형 값에 액세스할 수 있음을 나타냅니다.a
monad의 컨텍스트 내에서" : C. A. McCann[6]
보다 정확하게는 시나리오 고유의 이유로 값에 대한 무제한 액세스가 부적절한 경우 모나드를 사용할 수 있습니다.Maybe monad의 경우 값이 존재하지 않을 수 있기 때문입니다.IO 모나드의 경우, 예를 들어 모나드가 프롬프트가 표시된 후에만 제공되는 사용자 입력을 나타내는 경우 등 아직 값을 알 수 없기 때문입니다.모든 경우 접근이 적절한 시나리오는 모나드에 대해 정의된 바인드 조작에 의해 캡처됩니다.Maybe monad의 경우 값은 존재하는 경우에만 바인딩되며 IO 모나드의 경우 값은 시퀀스의 이전 작업이 실행된 후에 바인딩됩니다.
모나드는 유형 컨스트럭터 M과 다음 두 가지 연산을 정의함으로써 작성할 수 있습니다.return
(종종 단위라고도 함), 유형 값을 받습니다.a
그리고 그것을 타입의 모노디치 값으로 감싼다.m a
타입 컨스트럭터를 사용하여
return :: a -> M a
그리고.bind
(일반적으로 다음과 같이 표시됨)>>=
기능을 수신한다.)f
오버타이프a
모노디치 값을 변환할 수 있습니다.m a
적용.f
포장되지 않은 가치까지a
, 모나드 값을 반환한다.M b
:
bind :: (M a) -> (a -> M b) -> (M b)
(대안이지만 §에 상당하는 구성)join
대신 기능하다bind
연산자는 후술의 "함수로부터의 파생" 섹션에서 확인할 수 있습니다.
이 요소들로 프로그래머는 식에서 여러 개의 바인드 연산자가 함께 연결된 함수 호출의 시퀀스('파이프라인')를 구성합니다.각 함수 콜은 입력 플레인 타입의 값을 변환하고 바인드 연산자는 반환된 모나드 값을 처리합니다.이 값은 시퀀스의 다음 단계로 전송됩니다.
일반적으로 바인드 연산자는>>=
는 파라미터로 수신된 함수에서 사용할 수 없는 추가 계산 단계를 수행하는 모나드에 고유한 코드를 포함할 수 있습니다.구성된 함수 호출의 각 쌍 간에 바인드 연산자는 모나드 값에 삽입할 수 있습니다.m a
기능 내에서 접근할 수 없는 일부 추가 정보f
파이프라인에 전달합니다.또, 예를 들면, 특정의 조건하에서만 함수를 호출하거나, 특정의 순서로 함수 호출을 실행하거나 하는 것으로, 실행 플로우를 보다 세밀하게 제어할 수 있습니다.
예:아마도요.
모나드의 한 예는Maybe
type. 정의되지 않은 null 결과는 많은 프로시저 언어에서 처리용 특정 도구를 제공하지 않는 특정 과제 중 하나입니다. null 객체 패턴 또는 각 작업에서 정의되지 않은 값을 처리하기 위해 유효하지 않은 값을 테스트하기 위한 체크를 사용해야 합니다.이로 인해 버그가 발생하고 오류를 적절하게 처리하는 견고한 소프트웨어를 구축하기가 어려워집니다.그Maybe
type은 프로그래머가 결과의 두 가지 상태를 명시적으로 정의함으로써 잠재적으로 정의되지 않은 결과를 처리하도록 강제합니다.Just ⌑result⌑
, 또는Nothing
예를 들어, 프로그래머는 파서를 구성할 수 있습니다. 즉, 중간 결과를 반환하거나 파서가 검출한 조건과 프로그래머가 처리해야 하는 조건을 시그널링합니다.기능성 향신료를 조금 더 얹으면Maybe
type transforms를 완전 변환된 [b]: 12.3 pages 148-151 모나드로 만듭니다.
대부분의 언어에서 Maybe monad는 옵션 유형이라고도 하며, 값이 포함되어 있는지 여부를 표시하는 유형일 뿐입니다.일반적으로 이들은 일종의 열거형으로 표현됩니다.이 Rust의 예에서는, 이것을 「Rust」라고 부릅니다.Maybe<T>
이 유형의 변형은 일반 유형의 값일 수 있습니다. T
또는 빈 바리안트:Nothing
.
이<>//.T>제네릭 형식"T"을 나타냅니다. enum 아마도요.< >T> { 그저.(T), 아무 것도 없어요., }
Maybe<T>
어디서 유목민에 대한 연결이 들어오면 또한"포장"형식으로 이해할, 이건.의 어떤 형태로 언어로 쓰여 있어요Maybe
매개 변수 형식, 그들의 사용에서 이러한 서로 단항의 기능을 작곡하고 시험 도움이 된 기능을 가지고 있다. 만약 aMaybe
값이 들어 있다.
다음 메서드를 예를 들면, a에서Maybe
매개 변수 형식은 실패할까 기능의 결과로 이 경우는 형식 반환하다면 아무것도 아닌 divide-by-zero된다.
fn divide(x: 10 진수, y: 10 진수) -> Maybe < Decimal > y == 0 { return Nothing } } // divide(1.0, 4.0) -> Just(0.25) // divide(3.0, 0.0) -> 아무것도 반환하지 않음
테스트 방법 중 하나는,Maybe
사용할 값을 포함합니다.if
진술들.
허락하다 m_x = 나누다(3.14, 0.0); // 위의 나누기 함수 참조 // m_x 가 Maybe 의 Just 배리언트인 경우 if 문은 m_x 에서x 를 추출합니다. 한다면 허락하다 그저.(x) = m_x { 인쇄물("답변: ", x) } 또 다른 { 인쇄물("분할 실패, 0으로 나누기 오류...") }
허락하다 결과 = 나누다(3.0, 2.0); 경기 결과 { 그저.(x) => 인쇄물("답변: ", x), 아무 것도 없어요. => 인쇄물("분할 실패, 다음번엔 잡을 수 있을 거야"), }
모나드는 반환되는 함수를 구성할 수 있습니다.Maybe
함께.이를 위한 한 가지 구체적인 예는 하나의 함수를 도입하는 것입니다.Maybe
를 반환한다.a를 반환한다.Maybe
예를 들어 다음과 같습니다.
fn chainable_division(maybe_x: Maybe < Decimal >, maybe_y:Maybe<.Decimal>^->, Maybe<.Decimal>,{경기(maybe_x, maybe_y){(그냥()), Just(y))=>,{을 끓여만약 두가지 입력이 그냥, 반환 사단 복귀 Just(x/y).}, 즉 => 대가 없어 // 그렇지 않으면 복귀 없어}}chainable_division(chainable_division(그냥(2.0), Just(0.0)), Just(1.0). chainable_division 실패 안에//, 외부 chainable_division가 r아무것도 표시되지 않다
이 구체적인 예에서 Maybe를 사용하기 위해 함수를 다시 작성해야 하는 경우 많은 보일러 플레이트가 필요합니다(이러한 모든 것을 보십시오).Just
표현!)대신 바인드 연산자라고 하는 것을 사용할 수 있습니다.("맵", "플랫맵" 또는 "플랫맵"[8]: 2205s 이라고도 합니다).이 연산은 모나드를 반환하고 전달된 모나드의 내부 값에 대해 함수를 실행하여 함수에서 모나드를 반환하는 함수를 사용합니다.
// ".map"을 사용한 Rust 예제. maybe_x는 각각 Maybe <Decimal>와 Maybe <String>을 반환하는 2개의 함수를 통과합니다.// 일반 함수 구성과 마찬가지로 서로 공급되는 함수의 입력과 출력이 랩된 유형과 일치해야 합니다. (즉, add_one 함수는 Maybe <Decimal>을 반환해야 하며, Maybe_x: Maybe <Decimal> = Maybe_result = Maybe_x.map(x add_one(x) string)을 반환해야 합니다.
Haskell에는 연산자 바인드가 있습니다.또는>>=
함수 [c]: 150–151 구성과 유사한 보다 우아한 형태로 이 단일한 구성을 허용합니다.
절반으로 줄이다 :: 내부 -> 아마도요. 내부 절반으로 줄이다 x 심지어. x = 그저. (x `나누다` 2) 이상한 x = 아무 것도 없어요. -- 이 코드는 x를 2회 반감합니다.x가 4의 배수가 아니면 [없음]으로 평가됩니다. 절반으로 줄이다 x >>= 절반으로 줄이다
와 함께>>=
이용할 수 있는,chainable_division
익명 함수(예: 람다)의 도움을 받아 훨씬 간결하게 표현할 수 있습니다.다음 식에서 두 개의 중첩된 람다 각각이 전달된 랩된 값에 대해 어떻게 작동하는지 주목하십시오.Maybe
bind [d]: 93 연산자를 사용하여 모나드를 만듭니다.
체인 가능_분할(mx,나의) = mx >>= ( x개 -> 나의 >>= (y개 -> 그저. (x / y)) )
지금까지 보여 준 것은 기본적으로 모나드이지만, 보다 간결하게 말하면, 다음 섹션에서 정의한 모나드에 필요한 품질의 엄밀한 리스트를 다음에 나타냅니다.
- Monadic 타입
- A타입(
Maybe
) [b]: 148–151 。 - 유닛 조작
- 타입 컨버터(
Just(x)
) [d]: 93 。 - 바인드 조작
- 단항함수용 콤비네이터(
>>=
또는.map()
) [c]: 150–151 。
모나드 형성에 필요한 3가지 사항입니다.다른 모나드는 서로 다른 논리적 프로세스를 구현할 수 있으며, 일부는 추가적인 속성을 가질 수 있지만, 모두 이와 유사한 [1][9]세 가지 구성요소를 가집니다.
정의.
위의 예에서 사용된 함수 프로그래밍의 모나드에 대한 보다 일반적인 정의는 실제로 범주 이론의 표준 정의가 아닌 클라이슬리의 트리플 δT, δ, μ에 기초하고 있습니다.그러나 두 구조는 수학적으로 동일한 것으로 판명되었기 때문에 어느 하나의 정의가 유효한 모나드를 생성합니다.잘 정의된 기본 유형 T, U에서 모나드는 세 부분으로 구성됩니다.
- 모노딕 타입[e] M T를 구축하는 타입 컨스트럭터 M
- 유형 변환기(유닛 또는 리턴이라고도 함)로 객체 x를 모나드에 포함합니다.
unit : T → M T
[f] - 일반적으로 바인드라고 불리며(변수를 바인딩할 때처럼) infix 연산자로 표현되는 콤비네이터
>>=
또는 platMap이라고 불리는 메서드를 사용하여 모나드 변수를 압축 해제하고 모나드 함수/표현식에 삽입하여 새로운 모나드 값을 생성합니다.
단, 모나드로서의 자격을 완전히 갖추기 위해서는 다음 세 가지 법도 준수해야 합니다.
- unit은 bind의 왼쪽 끝자리입니다.
unit(x) >>= f
↔f(x)
- unit은 바인드의 오른쪽 방향이기도 합니다.
ma >>= unit
↔ma
- bind는 기본적으로 [h]연관성이 있습니다.
대수적으로, 이것은 어떤 모나드도 범주(클라이슬리 범주라고 함)와 함수 범주(값에서 계산까지)에서 모노이드를 발생시키고, 모노이드에서[8]: 2450s 이진 연산자로, 그리고 모나드에서 단위로서 모노이드를 발생시킨다는 것을 의미합니다.
사용.
모나드 패턴의 가치는 단순히 코드를 응축하고 수학적 추론에 대한 연결을 제공하는 것을 넘어선다.개발자가 사용하는 언어나 기본 프로그래밍 패러다임이 무엇이든 모나드 패턴을 따르는 것은 순수하게 기능적인 프로그래밍의 많은 이점을 가져옵니다.특정 종류의 계산을 재검증함으로써 모나드는 그 계산 패턴의 지루한 세부사항을 캡슐화할 뿐만 아니라 선언적인 방법으로 코드 선명도를 향상시킵니다.모노디치 값은 계산된 값뿐만 아니라 계산된 효과를 명시적으로 나타내므로 모노디치는 순수한 식과 마찬가지로 참조적으로 투명한 위치의 값으로 대체될 수 있으며, 이를 통해 많은 기술과 [4]개서를 기반으로 한 최적화가 가능합니다.
일반적으로 프로그래머는 bind to chain monadic functions to sequence를 사용하여 시퀀스를 만들 수 있으며,[1][5] 이로 인해 일부에서는 monad를 "프로그래밍 가능한 세미콜론"이라고 표현하기도 합니다.이것은 세미콜론을 사용하여 스테이트먼트를 구분하는 명령어 언어의 수에 대한 참조입니다.그러나, 모나드는 실제로 계산을 지시하지 않는다는 점을 강조해야 한다. 모나드를 중심 기능으로 사용하는 언어에서도 보다 단순한 함수 구성은 프로그램 내에서 단계를 배열할 수 있다.모나드의 일반적인 효용은 오히려 추상화를 [4][11]통해 프로그램 구조를 단순화하고 관심사 분리를 개선하는 데 있다.
모나드 구조는 데코레이터 패턴의 독특한 수학 및 컴파일 시간 변동으로도 볼 수 있습니다.일부 모나드는 함수에 액세스할 수 없는 추가 데이터를 전달할 수 있으며, 일부 모나드는 특정 조건에서만 함수를 호출하는 등 실행을 보다 세밀하게 제어합니다.이들은 애플리케이션 프로그래머가 미리 개발된 모듈로 보일러 플레이트 코드를 오프로드하면서 도메인 로직을 구현하도록 하기 때문에 모나드는 애스펙트 [12]지향 프로그래밍의 도구로 간주될 수도 있습니다.
모나드의 또 다른 주목할 만한 용도는 입력/출력 또는 가변 상태와 같은 부작용을 순수하게 기능하는 코드로 분리하는 것이다.순수하게 기능하는 언어라도 특히 [2]함수 구성과 연속 통과 스타일(CPS)의 혼합을 통해 모나드 없이 이러한 "불순한" 계산을 구현할 수 있습니다.그러나 모나드에서는 기본적으로 CPS 코드의 각 반복 패턴을 취하여 다른 [4]모나드로 번들함으로써 이 골격의 대부분을 추상화할 수 있습니다.
언어가 기본적으로 모나드를 지원하지 않는 경우에도 패턴을 구현할 수 있으며, 많은 경우 큰 어려움 없이 사용할 수 있습니다.범주이론에서 프로그래밍 용어로 번역할 때 모나드 구조는 일반적인 개념이며 경계다형성을 위해 동등한 기능을 지원하는 모든 언어로 직접 정의할 수 있습니다.기본 유형을 작업하는 동안 운영 세부 사항에 구애받지 않는 개념의 기능은 강력하지만, 모나드의 고유한 기능과 엄격한 동작으로 인해 다른 [13]개념과 차별화됩니다.
적용들
특정 모나드는 특정 계산 형태를 나타내기 때문에 특정 모나드에 대한 논의는 일반적으로 좁은 구현 문제를 해결하는 데 초점을 맞출 것이다.그러나 경우에 따라서는 애플리케이션이 핵심 논리 내에서 적절한 모나드를 사용함으로써 높은 수준의 목표를 달성할 수도 있습니다.
다음은 설계의 중심에 모나드가 있는 몇 가지 응용 프로그램입니다.
- Parsec 파서 라이브러리는 모나드를 사용하여 보다 단순한 파싱 규칙을 보다 복잡한 규칙으로 결합합니다.또한 소규모 도메인 고유의 언어에 [14]특히 유용합니다.
- xmonad는 지퍼 데이터 구조를 중심으로 한 타일 창 관리자이며, 그 자체가 구분된 [15]연속의 특정 사례로 일원적으로 취급될 수 있습니다.
- Microsoft의 LINQ는 에 대한 쿼리 언어를 제공합니다.쿼리 작성을 [16]위한 핵심 연산자를 포함한 기능 프로그래밍 개념의 영향을 많이 받는 NET 프레임워크.
- ZipperFS는 주로 지퍼 구조를 사용하여 기능을 [17]구현하는 단순하고 실험적인 파일 시스템입니다.
- Reactive Extensions 프레임워크는 기본적으로 옵저버 [18]패턴을 실현하는 데이터 스트림에 (공)모나딕인터페이스를 제공합니다.
역사
프로그래밍에서 "모나드"라는 용어는 실제로 순수하게 기능하는 경향이 있는 APL 및 J 프로그래밍 언어로 거슬러 올라갑니다.그러나 이러한 언어에서 "모나드"는 하나의 매개 변수(두 개의 매개 변수가 "다이아드"인 함수 등)[19]를 사용하는 함수의 약어일 뿐입니다.
수학자 로저 고덴셜은 1950년대 후반에 모나드의 개념을 처음으로 공식화했지만, "모나드"라는 용어는 범주 이론가인 손더스 맥 [citation needed]레인에 의해 널리 퍼졌다.그러나 바인드를 사용하여 위에서 정의한 형태는 수학자 하인리히 클라이슬리에 의해 1965년에 최초로 설명되었는데, 이는 모나드가 두 개의 (공변함수)[20] 함수 사이의 결합으로 특징지어질 수 있다는 것을 증명하기 위해서였다.
1980년대부터 모나드 패턴에 대한 막연한 개념이 컴퓨터 과학계에서 표면화되기 시작했다.프로그래밍 언어 연구자 필립 와들러에 따르면 컴퓨터 과학자 존 C. 레이놀즈는 1970년대와 1980년대 초에 연속 통과 스타일의 가치, 형식 의미론의 풍부한 원천으로서의 범주 이론, 값과 [4]계산 사이의 유형 구분을 논할 때 그것의 몇 가지 측면을 예상했습니다.1990년까지 활발하게 설계된 연구언어 Opal도 I/O를 모노딕 타입으로 효과적으로 기반으로 했지만 당시에는 [21]그 연관성이 실현되지 않았다.
컴퓨터 과학자인 Eugenio Moggi는 [22]1989년 컨퍼런스 논문에서 범주 이론의 모나드를 기능 프로그래밍과 명시적으로 연결시킨 최초의 사람이었고, 1991년 보다 정교한 저널 제출이 뒤따랐다.이전의 연구에서, 몇몇 컴퓨터 과학자들은 람다 미적분에 대한 의미론을 제공하기 위해 범주 이론을 사용하여 발전했다.Moggi의 핵심 통찰력은 실제 프로그램은 단순히 가치에서 다른 가치로의 함수가 아니라 그 가치를 계산하는 변환이라는 것이었다.범주이론적인 용어로 공식화하면 모나드가 [3]이러한 계산을 나타내는 구조라는 결론으로 이어진다.
필립 와들러와 사이먼 페이튼 존스를 포함한 몇몇 다른 사람들은 이 아이디어를 대중화했고 이 아이디어에 기반을 두었다. 그들은 둘 다 해스켈의 사양에 관여했다.특히 Haskell은 문제가 있는 "lazy stream" 모델을 v1.2까지 사용하여 I/O를 느린 평가와 조화시켜 보다 유연한 모노디 인터페이스로 [23]전환했습니다.Haskell 공동체는 계속해서 함수 프로그래밍의 많은 문제에 모나드를 적용했고, 2010년대에 Haskell과 함께 일하는 연구원들은 마침내 모나드가 적용 가능한 [24][i]함수이며 모나드와 화살표가 모두 모노이드라는 것을 [26]알아냈습니다.
처음에 모나드로 프로그래밍하는 것은 주로 하스켈과 그 파생어들로 한정되었지만, 함수 프로그래밍이 다른 패러다임에 영향을 미치면서, 많은 언어들이 모나드 패턴을 통합했다.공식은 현재 Scheme, Perl, Python, Racket, Clojure, Scala, F#에 존재하며 새로운 ML [citation needed]표준으로도 검토되고 있습니다.
분석.
모나드 패턴의 장점 중 하나는 계산 구성에 수학적 정밀도를 가져오는 것입니다.모나드 법칙을 사용하여 인스턴스의 유효성을 확인할 수 있을 뿐만 아니라 관련 구조(함수 등)의 피쳐도 서브타이핑을 통해 사용할 수 있습니다.
모나드법 확인
로 되돌아가다Maybe
예를 들어, 그 구성요소는 모나드를 구성한다고 선언되었지만, 모나드의 법칙을 충족한다는 증거는 주어지지 않았다.
이것은, 다음의 상세 내용을 삽입하는 것으로 해결할 수 있습니다.Maybe
일반 법칙의 한 변으로 만든 다음, 다른 변에 도달하기 위해 등가의 사슬을 대수적으로 구축합니다.
법칙 1: eta(a) >> = f(x) ( (a) > = f(x) f f(a)
법칙 2: ma >> = eta(x) ma ma가 (a)일 경우 eta(a) just Just a or Nothing nothing nothing if if if if끝이 없는 경우 끝은 없습니다
법칙 3:(엄마>>)f()))>>)g(y)⇔ 엄마>>)(f())>>)g(y))다면 엄마 그때 g(엄마>>)f()))(f())을(그냥)경우(엄마>>)f()))(그냥 b)은<>= g(y)) 다른 다른 아무것도 아무것도 끝.만약 끝 만약 ⇔ 만약 엄마 있는 경우 J.ust a) 및 f(a)는 (b)일 뿐이고, ma가 (a)이고 f(a)가 아무것도 아닌 경우 (g f f) other이다.
함수로부터의 파생
컴퓨터 과학에서는 드물지만, 모나드를 두 개의 추가적인 자연 [j]변환이 있는 펑터로 정의하는 범주 이론을 직접 사용할 수 있습니다.따라서 먼저 구조물에 함수 자격을 부여하려면 맵이라는 이름의 고차 함수(또는 "기능")가 필요합니다.
map φ : (a → b) → (ma → mb)
단, 이것이 항상 큰 문제는 아닙니다.특히 모나드가 기존 함수에서 파생되어 모나드가 자동으로 맵을 상속하는 경우에는 더욱 그렇습니다.(이력적인 이유로,map
대신, 라고 불리고 있습니다.fmap
해스켈에서).
모나드의 첫 번째 변환은 사실 클라이즐리 트리플과 같은 단위이지만 구조의 계층을 자세히 따라가면 모나드와 기본 펑터 사이의 중간 구조인 응용 펑터를 특징짓는다는 것이 밝혀졌습니다.적용 가능한 문맥에서 단위는 순수함수라고 불리기도 하지만 여전히 같은 함수입니다.이 구조에서 다른 점은 법칙 단위가 충족해야 한다는 것입니다. 바인드가 정의되지 않았기 때문에 대신 맵의 관점에서 제약이 주어집니다.
(unit ∘ φ) x ↔ ((map φ) ∘ unit) x
[27]적용함수에서 모나드로의 마지막 도약은 두 번째 변환인 결합함수(범주 이론에서는 보통 μ라고 불리는 자연 변환)와 함께 이루어지며, 이는 모나드의 중첩된 응용 프로그램을 "평탄화"시킵니다.
join(mma) : M (M T) → M T
특성 함수로서 결합은 모나드 [citation needed]법칙의 세 가지 변형도 충족해야 합니다.
(join ∘ (map join)) mmma ↔ (join ∘ join) mmma ↔ ma
(join ∘ (map unit)) ma ↔ (join ∘ unit) ma ↔ ma
(join ∘ (map map φ)) mma ↔ ((map φ) ∘ join) mma ↔ mb
개발자가 직접 모나드를 정의하든 Kleisli 트리플을 정의하든 기본 구조는 동일하며 양식은 서로 쉽게 파생될 수 있습니다.
(map φ) ma ↔ ma >>= (unit ∘ φ)
join(mma) ↔ mma >>= id
ma >>= f ↔ (join ∘ (map f)) ma
[28]다른 예: List
리스트 모나드는 더 단순한 함수에서 모나드를 도출하는 것이 얼마나 유용한지를 자연스럽게 보여준다.많은 언어에서 목록 구조는 몇 가지 기본 기능과 함께 미리 정의되어 있습니다.List
형식 생성자 및 추가 연산자(로 표시됨)++
infix 표기법의 경우)는 이미 여기에 제시된 것으로 가정합니다.
목록에 플레인 값을 포함하는 것도 대부분의 언어에서 간단합니다.
unit(x) = [x]
여기서부터 목록 이해 기능을 반복적으로 적용하는 것은 목록을 바인드하여 완전한 모나드로 변환하는 데 있어 쉬운 선택처럼 보일 수 있습니다.이 접근법의 어려움은 바인드가 모노딕 함수를 예상한다는 것입니다.이 경우 목록 자체가 출력됩니다.더 많은 함수가 적용되면 중첩된 목록의 레이어가 누적되어 기본적인 이해 이상의 것이 요구됩니다.
단, 목록 전체에 걸쳐 간단한 함수를 적용하는 절차, 즉 맵은 간단합니다.
(맵) xlist = [ ] 、 [ φx ( x 1 ) 、 ( x 2 ) ... 、 ( x n ) ]
이 두 가지 절차는 이미 촉진되고 있습니다List
해당 기능자에게 전달해야 합니다.모나드로서 완전한 자격을 얻으려면 반복된 구조를 평평하게 하기 위한 올바른 결합 개념만 필요합니다.단, 리스트의 경우 외부 리스트를 언랩하여 값을 포함하는 내부 리스트를 추가하는 것입니다.
join(xlist) = join([xlist1, xlist2, ..., xlistn]) = xlist1 ++ xlist2 ++ ...++ xlistn
결과 모나드는 리스트일 뿐만 아니라 함수가 적용되면 자동으로 크기가 조정되고 압축됩니다.바인드는 공식만으로 도출되어 피드용으로 사용될 수도 있습니다.List
단일 함수의 파이프라인을 통한 값:
(xlist >>= f) = join ∘ ( ( map f )xlist
이 모노딕 리스트의 1개의 애플리케이션은 비결정론적 계산을 나타내고 있습니다. List
는 알고리즘의 모든 실행 경로에 대한 결과를 보관 유지하고 각 단계에서 자신을 압축하여 어떤 경로가 어떤 결과로 이어졌는지 확인할 수 있습니다(결정론적 완전 알고리즘과 [citation needed]때로는 중요한 차이).또 다른 장점은 모나드에 체크를 내장할 수 있다는 것입니다.또한 [28]파이프라인에서 기능을 다시 쓸 필요 없이 특정 경로를 장애 발생 시 투과적으로 플루닝할 수 있습니다.
두 번째 상황은List
shines는 다치 함수를 구성하고 있습니다.예를 들어, 어떤 숫자의 n번째 복소수 루트는 n개의 구별된 복소수를 생성해야 하지만, 그 결과에서 다른 m번째 루트를 얻을 경우, 최종 m•n 값은 m•n번째 루트의 출력과 같아야 한다. List
는 이 문제를 완전히 자동화하여 각 단계의 결과를 수학적으로 올바른 플랫한 [29]목록으로 정리합니다.
기술
모나드는 단순한 프로그램 로직을 구성하는 것 이상의 흥미로운 기술을 제공할 수 있는 기회를 제공합니다.모나드는 높은 수준의 수학적 특성을 통해 상당한 추상화를 가능하게 하면서 유용한 구문적 특징을 위한 토대를 마련할 수 있습니다.
통사당할 수 있다
바인드를 공개적으로 사용하는 것이 종종 타당하지만, 많은 프로그래머들은 명령문을 모방하는 구문(해스켈에서는 do-notation, OCaml에서는 perform-notation, F#[30]에서는 연산식, Scala에서는 이해)을 선호한다.이것은 모노딕 파이프라인을 코드 블록으로 위장하는 통사적인 설탕일 뿐입니다.그러면 컴파일러는 이러한 표현들을 기본적인 함수 코드로 조용히 변환합니다.
의 번역add
에서 기능하다Maybe
Haskell로 변환하면 이 기능을 실제로 표시할 수 있습니다.의 비단독 버전add
Haskell에서는 다음과 같습니다.
더하다 mx 나의 = 사례. mx 의 아무 것도 없어요. -> 아무 것도 없어요. 그저. x -> 사례. 나의 의 아무 것도 없어요. -> 아무 것도 없어요. 그저. y -> 그저. (x + y)
모나드 해스켈에서return
plus lamda 표현식은 유닛의 표준명이고 명시적으로 처리되어야 하지만 이러한 기술적 문제에도 불구하고Maybe
monad는 보다 명확한 정의를 제공합니다.
더하다 mx 나의 = mx >>= (\x -> 나의 >>= (\y -> 돌아가다 (x + y)))
단, 주의사항을 사용하면 매우 직관적인 시퀀스로 요약할 수 있습니다.
더하다 mx 나의 = 하다 x <-> mx y <-> 나의 돌아가다 (x + y)
두 번째 예는 다음과 같습니다.Maybe
는 전혀 다른 언어로 사용할 수 있습니다.F#. 계산식에서 반환되는 "안전 분할" 함수None
정의되지 않은 피연산자 또는 0으로 나눗셈하는 경우 다음과 같이 쓸 수 있습니다.
허락하다 읽기 번호 () = 허락하다 s = 콘솔.라인 읽기() 허락하다 성공하다,v = Int32.TryParse(s) 한다면 (성공하다) 그리고나서 몇개(v) 또 다른 없음. 허락하다 secure_div = 아마도요. { 허락하다! x = 읽기 번호() 허락하다! y = 읽기 번호() 한다면 (y = 0) 그리고나서 없음. 또 다른 돌아가다 (x / y) }
빌드 시 컴파일러는 내부적으로 이 함수를 보다 밀도 높은 바인드 콜 체인으로 "탈설탕"합니다.
아마도요..지연(재밌어요 () -> 아마도요..바인드(읽기 번호(), 재밌어요 x -> 아마도요..바인드(읽기 번호(), 재밌어요 y -> 한다면 (y=0) 그리고나서 없음. 또 다른 아마도요..돌아가다(x / y))))
마지막 예에서는 일반적인 모나드 법칙 자체도 do-notation으로 표현할 수 있습니다.
하다 { x <-> 돌아가다 v; f x } == 하다 { f v } 하다 { x <-> m; 돌아가다 x } == 하다 { m } 하다 { y <-> 하다 { x <-> m; f x }; g y } == 하다 { x <-> m; y <-> f x; g y }
개발자는 편리하지만 이 블록 스타일은 완전히 구문적이어서 외관상으로는 모노딕(또는 비모노믹 CPS) 표현으로 대체할 수 있다는 점을 항상 기억해야 합니다.모노딕 파이프라인을 표현하기 위해 바인드를 사용하는 것은 여전히 많은 경우에 더 명확할 수 있으며, 일부 기능적 프로그래밍 옹호자들은 블록 스타일이 초보자들이 필수 프로그래밍으로부터 습관을 이어받을 수 있도록 허용하기 때문에 기본적으로는 피해야 하며 명백하게 [31][1]우수할 때만 사용해야 한다고 주장한다.
일반 인터페이스
모든 모나드는 모나드의 법칙을 충족하는 특정 구현을 필요로 하지만, 다른 구조나 언어 내의 표준 숙어와의 관계와 같은 다른 측면은 모든 모나드에 의해 공유됩니다.결과적으로, 언어 또는 라이브러리는 일반적인 정보를 제공할 수 있습니다.Monad
기능 프로토타입, 서브타이핑 관계 및 기타 일반적인 사실과의 인터페이스.개발에 앞서 새로운 모나드를 제공하고 슈퍼타입(예를 들어 펑터)에서 기능을 상속하는 것을 보증하는 것 외에 모나드의 설계를 인터페이스에 대해 체크하는 것은 품질 [citation needed]관리의 또 다른 레이어를 추가합니다.
연산자
모나드 코드는 연산자를 현명하게 사용함으로써 훨씬 더 단순화할 수 있습니다.맵 함수는 애드혹모나딕 함수 이상에서 동작하기 때문에 특히 유용합니다.단순함수가 미리 정의된 연산자와 유사하게 동작하는 한, 맵은 단순한 연산자를 단숨에 "리프트"[k]하기 위해 사용될 수 있습니다.이 기술을 사용하면add
에서Maybe
예는 다음과 같이 요약할 수 있다.
add(my,my) = 지도(+)
이 프로세스를 한 단계 더 진행하려면add
뿐만 아니라Maybe
, 그러나 전체적으로는Monad
인터페이스입니다.이를 통해 구조 인터페이스에 일치하고 자체 맵을 구현하는 모든 새로운 모나드는 즉시 리프팅된 버전의add
필요한 기능은 타입 시그니처의 일반화뿐입니다.
add : (모나드 번호, 모나드 번호)→ 모나드 번호[32]
분석에 유용한 또 다른 단항 연산자는 단항 합성(infix로 표시됨)입니다.>=>
여기서)를 사용하면 모노딕 함수를 보다 수학적인 스타일로 연결할 수 있습니다.
(f >=> g) x = (f(x) → mb) >> = g(y = b)
이 연산자를 사용하여 모나드 법칙은 함수만으로 작성할 수 있으며, 연관성과 동일성의 존재에 대한 대응성을 강조합니다.
(단위 > ↔ g) ↔ g (f > = > g) ↔ f (f > = > g) = h ↔ f > = > (g > = > [1]h )
또한 위의 내용은 Haskell에서 "do" 블록의 의미를 보여줍니다.
do p <- f(x) _q <- g(_p) h(_q) ↔ ( f > = > g > = > h )(x)
기타 예
아이덴티티 모나드
가장 단순한 모나드는 Identity 모나드로, 이는 모나드의 법칙을 만족시키기 위해 플레인 값과 함수에 주석을 달 뿐입니다.
new type Id T = T unit(x) = x (x >> = f) = f(x)
Identity
는 재귀적 모나드 변압기의 베이스 케이스를 제공하는 등 실제로 유효한 용도를 가지고 있습니다.명령형 [l][citation needed]블록 내에서 기본 변수 할당을 수행하는 데도 사용할 수 있습니다.
컬렉션
적절한 첨부가 있는 모든 컬렉션은 이미 무료 모노이드이지만, 알고보니List
잘 정의된 조인(join)을 가진 유일한 컬렉션은 아니며 모나드로 인정됩니다.돌연변이도 할 수 있다.List
특별한 속성을 [m][n]부가하는 것만으로 다른 모나드 컬렉션에 넣을 수 있습니다.
수집 | 모노이드 속성 |
---|---|
목록. | 공짜 |
유한 멀티셋 | 가환성 |
유한 집합 | 가환성 및 등가성 |
유한순열 | 비가환성 및 유휴성 |
IO 모나드(Haskell)
이미 언급했듯이 순수한 코드는 관리되지 않는 부작용을 가져서는 안 되지만, 그렇다고 해서 프로그램이 효과를 명시적으로 기술하고 관리하는 것을 막지는 않습니다.이 아이디어는 Haskell의 IO monad의 핵심이며, 여기서 오브젝트는IO a
유형 세계에 대한 정보를 선택적으로 제공하여 세계에서 수행되어야 할 작업을 설명하는 것으로 볼 수 있다.a
세상에 대한 정보를 제공하지 않는 행동은 다음과 같은 유형을 갖는다.IO ()
, 더미 값을 "확장"합니다.()
. 프로그래머가 바인드할 때IO
함수에 대한 값, 함수는 이전 액션(사용자, 파일 등으로부터의 입력)에 의해 제공된 세계에 대한 정보를 기반으로 수행할 다음 액션을 계산합니다.[23]가장 중요한 것은 IO 모나드의 값이 다른 IO 모나드를 계산하는 함수에만 바인딩될 수 있기 때문에 바인드 함수는 액션의 결과를 다음에 수행할 액션을 계산하는 함수에만 제공할 수 있는 일련의 액션의 규율을 부과한다.즉, 실행할 필요가 없는 액션은 절대 실행할 수 없으며 실행할 필요가 있는 액션은 명확하게 정의된 시퀀스를 가지므로 (IO) 액션이 참조적으로 투명하지 않다는 문제가 해결됩니다.
예를 들어 Haskell에는 파일이 존재하는지 확인하는 기능과 파일을 삭제하는 기능을 포함하여 더 넓은 파일 시스템에서 동작하는 여러 기능이 있습니다.두 가지 유형의 시그니처는 다음과 같습니다.
dos File Exists(존재 :: 파일 패스 -> 입출력 불 파일 삭제 :: 파일 패스 -> 입출력 ()
첫 번째는 특정 파일이 실제로 존재하는지 여부에 관심이 있으며 그 결과 부울 값이 출력됩니다.IO
반면, 두 번째 기능은 파일 시스템에서의 동작에만 관계되어 있기 때문에IO
출력하는 컨테이너가 비어 있습니다.
IO
는 파일 I/O에만 국한되지 않습니다.또한 사용자 I/O와 명령어 구문설탕을 사용하여 일반적인 "Hello, World!" 프로그램을 흉내낼 수도 있습니다.
주된 :: 입출력 () 주된 = 하다 putStrln "안녕, 세상아!" putStrln "사용자 이름이 뭐예요?" 이름. <-> 회선 putStrln ("반갑습니다." ++ 이름. ++ "!")
제외된 경우, 이는 다음 모노딕 파이프라인으로 변환됩니다(>>
in Haskell은 단일 효과만 중요하고 기본 결과를 폐기할 수 있는 경우 바인딩의 변형일 뿐입니다).
주된 :: 입출력 () 주된 = putStrln "안녕, 세상아!" >> putStrln "사용자 이름이 뭐예요?" >> 회선 >>= (\이름. -> putStrln ("반갑습니다." ++ 이름. ++ "!"))
라이터 모나드(JavaScript)
또 다른 일반적인 상황은 로그 파일을 보관하거나 프로그램의 진행 상황을 보고하는 것입니다.때때로 프로그래머는 나중에 프로파일링 또는 디버깅하기 위해 보다 구체적인 기술 데이터를 기록할 수 있습니다.Writer 모나드는 단계별로 누적되는 보조 출력을 생성하여 이러한 작업을 처리할 수 있습니다.
이 예에서는 모나드 패턴이 주로 기능하는 언어로 제한되지 않는 방법을 보여 주기 위해Writer
monad를 입력합니다.첫째, (내스트된 꼬리가 있는) 어레이를 사용하면Writer
를 링크 목록으로 입력합니다.기본 출력값은 어레이 위치0에 존재하며 위치1은 암묵적으로 보조노트의 체인을 유지합니다.
컨스턴트 작가. = 가치 => [가치, []];
유닛의 정의도 매우 간단합니다.
컨스턴트 구성 단위 = 가치 => [가치, []];
출력하는 단순한 함수를 정의하는 데 필요한 것은 단위뿐입니다.Writer
디버깅 노트가 있는 오브젝트:
컨스턴트 정사각형 = x => [x * x, [`${x}정사각형이었습니다.`]]; 컨스턴트 반토막 났다 = x => [x / 2, [`${x}반으로 줄었습니다.`]];
진정한 모나드는 여전히 바인드가 필요하지만Writer
이는 단순히 함수의 출력을 모나드의 링크 목록에 추가하는 것과 같습니다.
컨스턴트 묶다 = (작가., 변혁) => { 컨스턴트 [가치, 로그.] = 작가.; 컨스턴트 [결과, 갱신] = 변혁(가치); 돌아가다 [결과, 로그..콘센트(갱신)]; };
샘플 함수는 바인드를 사용하여 체인으로 연결할 수 있지만, 모노딕 합성 버전(라 불린다)을 정의합니다.pipelog
여기서)를 사용하면 다음 기능을 더욱 간결하게 적용할 수 있습니다.
컨스턴트 파이프 로그 = (작가., ...변환) => 변환.줄이자(묶다, 작가.);
최종적인 결과는 계산의 단계적 처리와 나중에 감사하기 위한 로그 기록 사이의 문제를 완전히 분리하는 것입니다.
파이프 로그(구성 단위(4), 정사각형, 반토막 났다); // 결과 작성자 개체 = [8, ['4'는 제곱되었습니다. '16은 반으로 줄었습니다.']
환경 모나드
환경 모나드(리더 모나드 및 함수 모나드라고도 함)를 사용하면 공유 환경의 값에 따라 계산이 달라집니다.모나드 유형 생성자는 유형 T를 유형 E → T의 함수에 매핑합니다. 여기서 E는 공유 환경의 유형입니다.모나드 함수는 다음과 같습니다.
다음과 같은 단항 연산이 유용합니다.
ask 조작은 현재 콘텍스트를 취득하기 위해 사용되며 local은 변경된 서브 콘텍스트에서 계산을 수행합니다.상태 모나드와 마찬가지로 환경 값을 제공하고 이를 모나드의 인스턴스에 적용함으로써 환경 모나드의 계산을 호출할 수 있다.
형식적으로 환경 모나드의 값은 추가적인 익명 인수를 갖는 함수와 동일하며, 반환과 바인드는 각각 SKI 결합기 미적분의 K와 S 결합기와 동일하다.
스테이트 모나드
상태 모나드는 프로그래머가 어떤 유형의 상태 정보를 계산에 부가할 수 있도록 한다.모든 값 유형이 지정되면 상태 모나드의 해당 유형은 상태를 받아들인 다음 새로운 상태(유형)를 출력하는 함수입니다.s
(타입의) 반환값과 함께t
이는 환경모나드와 비슷하지만 새로운 상태를 반환하기 때문에 변경 가능한 환경을 모델링할 수 있다는 점이 다릅니다.
유형 주 s t = s -> (t, s)
이 모나드는 상태 정보의 유형인 type 파라미터를 사용합니다.모나드 연산은 다음과 같이 정의됩니다.
-- "return"은 상태를 변경하지 않고 지정된 값을 생성합니다. 돌아가다 x = \s -> (x, s) -- "m"은 결과에 f를 적용하도록 m을 변경합니다. m >>= f = \r -> 허락하다 (x, s) = m r 에 (f x) s
유용한 상태 운영은 다음과 같습니다.
얻다 = \s -> (s, s) -- 계산의 현시점에서의 상태를 조사합니다. 놓다 s = \_ -> ((), s) -- 상태를 바꿉니다. 수정하다 f = \s -> ((), f s) -- 상태를 갱신합니다.
다른 조작에서는, 스테이트 모나드가 소정의 초기 스테이트에 적용됩니다.
실행 상태 :: 주 s a -> s -> (a, s) 실행 상태 t s = t s
상태 모나드의 do-blocks는 상태 데이터를 검사하고 업데이트할 수 있는 일련의 작업입니다.
비공식적으로 상태 유형 S의 상태 모나드는 반환값 T의 유형을 S × {\ S S의 함수에 매핑합니다.여기서 S는 기본 상태입니다.return 및 bind 함수는 다음과 같습니다.
- 귀환:T→ S→ T×S)t↦ s↦(t, s)바인드:(S→ T×S)→(T→ S→ T′×S)→ S→ T′×S)m↦ k↦ s↦(k가 있어 ′)이(t, s′))ms{\displaystyle{\begin{배열}{ 주어}{\text{반환}}\colon&.T\rightarrow S\rightarrow T\times S=t\mapsto s\mapsto(t,s)\\{\text{바인드}}\colon&(S\rightarrow T\t. S S T S\mapsto (kt\s\mapsto (k\text{}\(
범주 이론의 관점에서, 상태 모나드는 정의상 모든 데카르트 닫힌 범주에 존재하는 곱 함수자와 지수 함수자 사이의 결합에서 도출된다.
계속 모나드
리턴 타입 R의 연속 모나드는[o] 타입 T를 타입 { \(T Rarrow 의 함수로 매핑하며 연속 화살표 스타일을 모델링하는 데 사용됩니다.return 및 bind 함수는 다음과 같습니다.
call-with-current-continuation 함수는 다음과 같이 정의됩니다.
프로그램 로깅
다음 코드는 의사 코드입니다.두 가지 함수가 있다고 가정합니다.foo
그리고.bar
, 타입 포함
후우 : 인트 -> 인트 막대기 : 인트 -> 인트
즉, 두 함수 모두 정수를 받아들이고 다른 정수를 반환합니다.그런 다음 다음과 같이 함수를 연속으로 적용할 수 있습니다.
후우 (막대기 x)
여기서 그 결과는foo
결과에 적용되다bar
에 적용되다x
.
그러나 프로그램을 디버깅하고 로그 메시지를 에 추가한다고 가정합니다.foo
그리고.bar
따라서 다음과 같이 유형을 변경합니다.
후우 : 인트 -> 인트 * 스트링 막대기 : 인트 -> 인트 * 스트링
따라서 두 함수는 응용 프로그램 결과를 정수로 하는 태플을 반환하고 적용된 함수 및 이전에 적용된 모든 기능에 대한 정보를 포함하는 로깅 메시지를 문자열로 반환합니다.
불행히도, 이것은 우리가 더 이상 작곡을 할 수 없다는 것을 의미한다. foo
그리고.bar
, 입력 타입으로서int
출력 타입과 호환되지 않습니다.int * string
그리고 각 기능의 종류를 수정함으로써 다시 컴포넌트성을 얻을 수 있지만int * string -> int * string
이를 위해서는 각 함수에 보일러 플레이트 코드를 추가하여 태플에서 정수를 추출해야 합니다.태플에서 정수를 추출하는 것은 이러한 함수의 수가 증가함에 따라 지루해집니다.
대신 도우미 기능을 정의하여 이 보일러 플레이트를 추상화합니다.
묶다 : 인트 * 스트링 -> (인트 -> 인트 * 스트링) -> 인트 * 스트링
bind
정수 및 문자열 태플을 받아들인 다음 함수를 받아들입니다(예:foo
)는 정수에서 정수 및 문자열 태플에 매핑됩니다.출력은 정수와 문자열 태플입니다.이것은 입력 정수와 문자열 태플 내의 정수에 입력 함수를 적용한 결과입니다.이 방법으로, 우리는 태플에서 정수를 추출하기 위해 보일러 플레이트 코드를 작성하면 됩니다.bind
.
이제 우리는 어느 정도 구성성을 되찾았다.예를 들어 다음과 같습니다.
묶다 (묶다 (x,s) 막대기) 후우
어디에(x,s)
는 정수 및 문자열 태플입니다.[p]
이점을 더욱 명확하게 하기 위해 infix 연산자를 에일리어스로 정의합시다.bind
:
(>>=) : 인트 * 스트링 -> (인트 -> 인트 * 스트링) -> 인트 * 스트링
하도록t >>= f
와 같다bind t f
.
다음으로 위의 예를 제시하겠습니다.
((x,s) >>= 막대기) >>= 후우
마지막으로, 글을 쓰지 않아도 된다면 좋을 것 같습니다.(x, "")
빈 로깅 메시지를 작성할 때마다 여기서""
빈 문자열입니다.이제 새로운 함수를 정의하겠습니다.
돌아가다 : 인트 -> 인트 * 스트링
어느쪽이 랩인가?x
위에 설명된 튜플에 있습니다.
이제 메시지 로깅을 위한 훌륭한 파이프라인이 제공됩니다.
((돌아가다 x) >>= 막대기) >>= 후우
이를 통해 보다 쉽게 결과를 기록할 수 있습니다.bar
그리고.foo
에x
.
int * string
에 의사 코드화된 모나드 [p]값을 나타냅니다. bind
그리고.return
는, 같은 이름의 대응하는 함수와 유사합니다.실은.int * string
,bind
,그리고.return
모나드를 형성하다
바리에이션
수학적인 수준에서, 일부 모나드는 특히 좋은 속성을 가지고 있고 특정 문제에 독특하게 적합됩니다.
가법 모나드
가법 모나드는 mzero라고 불리는 mplus 아래의 추가 닫힌, 연관된 이진 연산자 mplus와 식별 요소를 가진 모나드입니다.그Maybe
모나드는 첨가물로 간주될 수 있다.Nothing
mzero 및 OR 연산자의 변동을 mplus로 나타냅니다. List
또한 빈 목록이 있는 추가 모나드입니다.[]
mzero 및 연결 연산자로 기능합니다.++
mplus로 지정합니다.
직관적으로 mzero는 기본 유형의 값이 없는 모나드 래퍼를 나타내지만 바인드의 흡수체 역할을 하기 때문에 (1이 아닌) "제로"로도 간주되며 모나드 함수에 바인딩될 때마다 mzero를 반환합니다.이 속성은 양면이며, 임의의 값이 Monadic Zero 함수에 바인드되어 있는 경우에도 bind는 mzero를 반환합니다.
범주이론에서, 가법 모나드는 바인드가 있는 모노이드 함수(모든 모노드처럼)에 대한 모노이드로 한 번 수식하고 [33][q]mplus를 통해 다시 모노리드 값에 대해 수식한다.
프리 모나드
때때로 모나드의 일반적인 윤곽이 유용할 수 있지만, 어떤 단순한 패턴도 모나드를 권장하지 않습니다.이것이 바로 자유로운 모나드가 필요한 부분이다; 모나드의 범주에서 자유로운 개체로서 모나드의 법칙 자체를 넘어서는 특별한 제약 없이 모나드 구조를 나타낼 수 있다.자유 모노이드가 평가 없이 요소를 연결하는 것처럼, 자유 모노이드는 형식 시스템을 만족시키기 위해 마커와 계산을 연결할 수 있지만, 그렇지 않으면 더 깊은 의미론 자체를 부과하지 않습니다.
예를 들어, 이 모든 작업을Just
그리고.Nothing
마커,Maybe
모나드는 사실 무료 모나드입니다.그List
반면 모나드는 목록에 대한 추가적이고 구체적인 사실을 정의에 포함시키기 때문에 무료 모나드는 아닙니다.마지막 예는 추상적인 무료 모나드입니다.
데이터. 공짜 f a = 순수하다 a 공짜 (f (공짜 f a)) 구성 단위 :: a -> 공짜 f a 구성 단위 x = 순수하다 x 묶다 :: 펑터 f => 공짜 f a -> (a -> 공짜 f b) -> 공짜 f b 묶다 (순수하다 x) f = f x 묶다 (공짜 x) f = 공짜 (fmap (\y -> 묶다 y f) x)
그러나 프리 모나드는 이 예시와 같이 링크 목록에 제한되지 않으며 나무와 같은 다른 구조물을 중심으로 구축될 수 있습니다.
처음에는 의도적으로 무료 모나드를 사용하는 것이 비현실적으로 보일 수 있지만, 그 형식적인 성격은 통사적인 문제에 특히 적합합니다.프리 모나드는 구문 및 유형을 추적하는 데 사용할 수 있으며, 의미론은 나중에 사용할 수 있도록 남겨두기 때문에 [34]파서 및 인터프리터에서 사용할 수 있습니다.또,[35] 언어내에서 반복을 실시하는 등, 보다 동적인 운용상의 문제에도 적용하고 있습니다.
코모나드
추가 속성을 가진 모나드를 생성하는 것 외에, 주어진 모나드에 대해 코모나드를 정의할 수도 있습니다.개념적으로, 모나드가 기본 값에서 축적된 계산을 나타내는 경우, 코모나드는 다시 값으로 환원되는 것으로 볼 수 있다.어떤 의미에서 모나드 코드는 완전히 "해동"할 수 없습니다.값이 모나드 내에서 랩되면 부작용과 함께 격리된 상태로 유지됩니다(순수하게 기능하는 프로그래밍에서는 좋은 점).그러나 때로는 코모나드가 명시적으로 모델링할 수 있는 상황별 데이터를 소비하는 것이 문제가 되기도 합니다.
엄밀히 말하면 코모나드는 모나드의 범주형 듀얼입니다.즉, 형식 시그니처의 방향이 반대인 경우에만 필요한 동일한 컴포넌트를 갖는다는 의미입니다.바인드 중심 모나드 정의에서 코모나드는 다음과 같이 구성됩니다.
- 고차 타입 W T를 마크하는 타입 컨스트럭터 W
- 여기서 counit이라고 하는 유닛의 쌍수는 코모나드에서 기본 값을 추출한다.
counit(wa): W T → T
- 바인드의 반전(또한 로 표시됨)
=>>
)는 다음과 같은 기능 축소를 확장합니다.
(wa =>> f) : (W U, W U → T) → W T[r]
확장 및 위원회는 또한 모나드 법률의 이중성을 충족해야 한다.
counit → (wa => f) → wb ) ↔ f(wa) → b wa = > counit ↔ wa ( ( (=>> f(wx = wa)) → wb (wa > g (wx = wa) → wa (wa) > wa (w) = wa (wa > f(wa) > wa) = wa > wa) > wa > wa > wa = wa (wa)
모나드와 마찬가지로 코모나드는 결합의 이중을 사용하여 함수에서 파생될 수 있다.
- duplicate는 이미 혼재된 값을 가져와 다른 혼재 구조 레이어로 래핑합니다.
duplicate(wa): W T → W (W T)
그러나 확장과 같은 연산은 반대로 진행되지만, 코모나드는 그것이 작용하는 함수를 되돌리지 않으며, 결과적으로 코모나드는 여전히 공동 함수가 아닌 맵을 가진 함수입니다.duplicate, councit 및 map을 사용하는 대체 정의도 자체 코모나드 법칙을 따라야 합니다.
(맵 중복) wa ↔ (맵 중복) wa ↔ wwwa ((맵 counit) ∘ duplicate ) wa ↔ (맵 중복) wa ↔ (맵 중복) wa ↔ (맵 중복) wa ↔ wwb
또한 모나드와 마찬가지로 두 가지 형태를 자동으로 변환할 수 있습니다.
(맵) wa ↔ wa = > (카운트) wx 중복 wa ↔ > wx
wa = >> f(wx) ↔ ((map f)의 중복) wa
간단한 예로는 입력값과 공유 환경 데이터를 기반으로 값을 출력하는 제품 코모나드가 있습니다.실제로,Product
comonad는 단지 두 가지 요소일 뿐입니다.Writer
모나드이며 실질적으로 같은Reader
monad(둘 다 다음에 설명) Product
그리고.Reader
수용하는 기능 시그니처와 값을 래핑 또는 래핑 해제하여 이러한 기능을 보완하는 방법만 다를 뿐입니다.
간단한 예는 스트림 코모나드로, 데이터 스트림을 표현하고 extend를 사용하여 수신 신호에 필터를 부착할 수 있습니다.실제로 모나드만큼 인기 있는 코모나드는 아니지만 데이터 흐름 프로그래밍 [36][37]스트림 처리 및 모델링에 특히 유용한 것으로 연구진은 밝혀졌습니다.
그러나 엄격한 정의 때문에 모나드와 코모나드 사이를 단순히 왔다 갔다 할 수는 없다.한층 더 높은 추상화로서 화살표는 양쪽의 구조를 상정할 수 있지만, 단항 코드와 혼항 코드를 조합하는 보다 세밀한 방법을 찾는 것은 활발한 [38][39]연구 영역이다.
「 」를 참조해 주세요.
계산 모델링의 대안:
관련 설계 개념:
- 애스펙트 지향 프로그래밍은 보조 부기 코드를 분리하여 모듈화와 단순성을 개선합니다.
- 제어의 반전은 중요한 프레임워크에서 특정 함수를 호출하는 추상적인 원리입니다.
- 유형 클래스는 Haskell에서 모나드 및 기타 구조를 구현하기 위해 사용되는 특정 언어 기능입니다.
- 데코레이터 패턴은 객체 지향 프로그래밍에서 유사한 이점을 얻기 위한 보다 구체적이고 임시적인 방법입니다.
모나드의 일반화:
- 응용 펑터는 단위와 지도와 관련된 법칙만 유지함으로써 모나드에서 일반화한다.
- 화살표는 추가 구조를 사용하여 플레인 기능과 모노드를 단일 인터페이스로 구현
- 모나드 변압기는 서로 다른 모나드에 작용하여 모듈식으로 결합합니다.
메모들
- ^ 프로그래밍에서는 여러 자유 변수에 대한 함수가 일반적이기 때문에, 이 기사에서 설명한 바와 같이, 이론가들은 기술적으로 강력한 [3]모나드라고 부른다.
- ^ a b Maybe의 구체적인 동기는 (Hutton 2016)[7]에서 확인할 수 있습니다.
- ^ a b Hutton은 을 추상화한다.
bind
실패할 수 있는 유형 a와 실패할 수 있는 매핑 a→b가 주어지면 실패할 수 있는 결과 b가 생성됩니다.(Hutton, 2016)[7] - ^ a b (Hutton 2016)에서는 Just는 Success를 나타내고 Nothing은 [7]Failure를 나타낼 수 있다고 합니다.
- ^ 의미론적으로 M은 사소한 것이 아니며 모든 잘 입력된 값의 범주에 대한 endofunctor를 나타냅니다.
- ^ 프로그래밍 용어로 (파라메트릭 다형성) 함수는 수학적으로 자연스러운 변환이지만, 단위(범주 이론에서는 종종 A: i ( ) ( a ) : \ \ _{A ; \ mathrm {} { \ { A} { } } 。
- ^ 반면 바인드는 범주 이론에서 자연스러운 변환이 아니라 매핑(값에서 계산으로)을 계산 사이의 형태론으로 끌어올리는 확장- : l ( B) , F : ( ) ( ) ( V A )→ ( )
- ^ 엄밀히 말하면, 바인드는 수학이 아닌 람다 미적분에서의 적용에 해당하기 때문에 모든 상황에서 공식적으로 연관성이 있는 것은 아닐 수 있습니다.엄밀한 람다 계산에서 바인드를 평가하려면 먼저 오른쪽 항(2개의 모나드 값을 바인딩할 때) 또는 어나니머스 함수에서 바인딩 자체를 래핑해야 합니다.[10]
- ^ GHC 버전 7.10.1 이후 Haskell은 Haskell의 2014 Application Monad Proposal(AMP)을 적용하기 시작했습니다.이것에 의해, 모나드를 [25]사용하는 기존의 모듈에 7 행의 코드를 삽입할 필요가 있습니다.
- ^ 이러한 자연 변환은 보통 형태소 δ, μ로 표시됩니다.즉, δ, μ는 단위, join은 결합을 나타낸다.
- ^ Haskell과 같은 몇몇 언어들은 심지어 라고 불리는 다른 맥락에서 지도의 가명을 제공한다.
lift
파라미터 카운트가 다른 여러 버전과 함께 자세한 내용은 무시됩니다. - ^ 범주 이론에서,
Identity
또한 모나드는 그 역함수와 함수의 결합에서 나타나는 것으로 볼 수 있다. - ^ 범주 이론은 이러한 집합 모노드를 집합 범주에서 모노이드의 범주까지 자유 함수자와 다른 함수자 사이의 결합으로 봅니다.
- ^ 여기서 프로그래머의 과제는 적절한 모노이드를 구성하거나 라이브러리에서 모노이드를 선택하는 것입니다.
- ^ 독자는 McCann의 스레드를[6] 따라 아래의 유형과 비교할 수 있습니다.
- ^ a b 이 경우,
bind
에 붙었다.string
이전에는 단지integer
있었다. 즉, 프로그래머가 부가 명령어를 구성했다: 태플(x,s)
(을 나타냄)int * string
위 의사 코드 above 。 - ^ 대수적으로, 두 (비교환적) 모노이드 측면 사이의 관계는 거의 반주기의 그것과 유사하며, 일부 첨가물 모노드는 그렇게 인정된다.그러나, 모든 가법적 모나드가 [33]근일기의 분포 법칙을 만족하는 것은 아니다.
- ^ Haskell에서는 실제로 익스텐드는 입력이 교환된 상태에서 정의되지만, 이 문서에서는 커링이 사용되지 않기 때문에 여기서 바인드의 정확한 쌍으로 정의됩니다.
레퍼런스
- ^ a b c d e f g O'Sullivan, Bryan; Goerzen, John; Stewart, Don (2009). "Monads". Real World Haskell. Sebastopol, California: O'Reilly Media. chapter 14. ISBN 978-0596514983.
- ^ a b Wadler, Philip (June 1990). Comprehending Monads. ACM Conference on LISP and Functional Programming. Nice, France. CiteSeerX 10.1.1.33.5381.
- ^ a b c Moggi, Eugenio (1991). "Notions of computation and monads" (PDF). Information and Computation. 93 (1): 55–92. CiteSeerX 10.1.1.158.5275. doi:10.1016/0890-5401(91)90052-4.
- ^ a b c d e Wadler, Philip (January 1992). The essence of functional programming. 19th Annual ACM Symposium on Principles of Programming Languages. Albuquerque, New Mexico. CiteSeerX 10.1.1.38.9516.
- ^ a b Hudak, Paul; Peterson, John; Fasel, Joseph (1999). "About Monads". A Gentle Introduction to Haskell 98. chapter 9.
- ^ a b C. A. McCann의 답변(Jul 23'10 23:39) Haskell Cont 모나드는 어떻게 그리고 왜 작동합니까?
- ^ a b c Graham Hutton (2016) Haskell 제2판 프로그래밍
- ^ a b Beckerman, Brian (21 November 2012). "Don't fear the Monad". YouTube.
{{cite web}}
: CS1 maint :url-status (링크) - ^ Spivey, Mike (1990). "A functional theory of exceptions" (PDF). Science of Computer Programming. 14 (1): 25–42. doi:10.1016/0167-6423(90)90056-J.
- ^ "Monad laws". HaskellWiki. haskell.org. Retrieved 14 October 2018.
- ^ "What a Monad is not". 7 October 2018.
- ^ De Meuter, Wolfgang (1997). Monads as a theoretical foundation for AOP (PDF). International Workshop on Aspect Oriented Programming at ECOOP. Jyväskylä, Finland. CiteSeerX 10.1.1.25.8262.
- ^ "Monad (sans metaphors)". HaskellWiki. 1 November 2009. Retrieved 24 October 2018.
- ^ O'Sullivan, Bryan; Goerzen, John; Stewart, Don (2009). "Using Parsec". Real World Haskell. Sebastopol, California: O'Reilly Media. chapter 16. ISBN 978-0596514983.
- ^ Stewart, Don (17 May 2007). "Roll Your Own Window Manager: Tracking Focus with a Zipper". Control.Monad.Writer. Archived from the original on 20 February 2018. Retrieved 19 November 2018.
- ^ Benton, Nick (2015). "Categorical Monads and Computer Programming" (PDF). London Mathematical Society Impact150 Stories. 1. Retrieved 19 November 2018.
- ^ Kiselyov, Olag (2007). "Delimited Continuations in Operating Systems". Modeling and Using Context. Lecture Notes in Computer Science. Springer Berlin Heidelberg. 4635. pages 291--302. doi:10.1007/978-3-540-74255-5_22. ISBN 978-3-540-74255-5.
- ^ Meijer, Erik (27 March 2012). "Your Mouse is a Database". ACM Queue. 10 (3): 20–33. doi:10.1145/2168796.2169076. Retrieved 19 November 2018.
- ^ Iverson, Kenneth (September 1987). "A dictionary of APL". APL Quote Quad. 18 (1): 5–40. doi:10.1145/36983.36984. ISSN 1088-6826. S2CID 18301178. Retrieved 19 November 2018.
- ^ Kleisli, Heinrich (1965). "Every standard construction is induced by a pair of adjoint functors" (PDF). Proceedings of the American Mathematical Society. 16 (3): 544–546. doi:10.1090/S0002-9939-1965-0177024-4. Retrieved 19 November 2018.
- ^ Peter Pepper, ed. (November 1997). The Programming Language Opal (Technical report) (5th corrected ed.). Fachbereich Informatik, Technische Universität Berlin. CiteSeerX 10.1.1.40.2748.
- ^ Moggi, Eugenio (June 1989). Computational lambda-calculus and monads (PDF). Fourth Annual Symposium on Logic in computer science. Pacific Grove, California. CiteSeerX 10.1.1.26.2787.
- ^ a b Peyton Jones, Simon L.; Wadler, Philip (January 1993). Imperative functional programming (PDF). 20th Annual ACM Symposium on Principles of Programming Languages. Charleston, South Carolina. CiteSeerX 10.1.1.53.2504.
- ^ 브렌트 요르게이 타입클래식 사전
- ^ 스택 오버플로(2017년 9월 8일) Haskell에서 새로운 모나드를 정의하면 Application 인스턴스가 발생하지 않음
- ^ 브렌트 요르게이 모노이드
- ^ "Applicative functor". HaskellWiki. Haskell.org. 7 May 2018. Archived from the original on 30 October 2018. Retrieved 20 November 2018.
- ^ a b Gibbard, Cale (30 December 2011). "Monads as containers". HaskellWiki. Haskell.org. Archived from the original on 14 December 2017. Retrieved 20 November 2018.
- ^ a b Piponi, Dan (7 August 2006). "You Could Have Invented Monads! (And Maybe You Already Have.)". A Neighborhood of Infinity. Archived from the original on 24 October 2018. Retrieved 16 October 2018.
- ^ "Some Details on F# Computation Expressions". Retrieved 9 October 2018.
- ^ "Do notation considered harmful". HaskellWiki. Retrieved 12 October 2018.
- ^ Giles, Brett (12 August 2013). "Lifting". HaskellWiki. Haskell.org. Archived from the original on 29 January 2018. Retrieved 25 November 2018.
- ^ a b Rivas, Exequiel; Jaskelioff, Mauro; Schrijvers, Tom (July 2015). From monoids to near-semirings: the essence of MonadPlus and Alternative (PDF). 17th International ACM Symposium on Principles and Practice of Declarative Programming. Siena, Italy. CiteSeerX 10.1.1.703.342.
- ^ Swierstra, Wouter (2008). "Data types à la carte" (PDF). Functional Pearl. Journal of Functional Programming. Cambridge University Press. 18 (4): 423–436. CiteSeerX 10.1.1.101.4131. doi:10.1017/s0956796808006758. ISSN 1469-7653. S2CID 21038598.
- ^ Kiselyov, Oleg (May 2012). Schrijvers, Tom; Thiemann, Peter (eds.). Iteratees (PDF). International Symposium on Functional and Logic Programming. Lecture Notes in Computer Science. Vol. 7294. Kobe, Japan: Springer-Verlag. pp. 166–181. doi:10.1007/978-3-642-29822-6_15. ISBN 978-3-642-29822-6.
- ^ Uustalu, Tarmo; Vene, Varmo (July 2005). Horváth, Zoltán (ed.). The Essence of Dataflow Programming (PDF). First Summer School, Central European Functional Programming. Lecture Notes in Computer Science. Vol. 4164. Budapest, Hungary: Springer-Verlag. pp. 135–167. CiteSeerX 10.1.1.62.2047. ISBN 978-3-540-46845-5.
- ^ Uustalu, Tarmo; Vene, Varmo (June 2008). "Comonadic Notions of Computation". Electronic Notes in Theoretical Computer Science. Elsevier. 203 (5): 263–284. doi:10.1016/j.entcs.2008.05.029. ISSN 1571-0661.
- ^ Power, John; Watanabe, Hiroshi (May 2002). "Combining a monad and a comonad" (PDF). Theoretical Computer Science. Elsevier. 280 (1–2): 137–162. CiteSeerX 10.1.1.35.4130. doi:10.1016/s0304-3975(01)00024-x. ISSN 0304-3975.
- ^ Gaboardi, Marco; Katsumata, Shin-ya; Orchard, Dominic; Breuvart, Flavien; Uustalu, Tarmo (September 2016). Combining Effects and Coeffects via Grading (PDF). 21st ACM International Conference on Functional Programming. Nara, Japan: Association for Computing Machinery. pp. 476–489. doi:10.1145/2951913.2951939. ISBN 978-1-4503-4219-3.
외부 링크
HaskellWiki 참조:
- 「모나드의 모든 것」(원제: Jeff Newbern) - 일반적인 모든 모나드와 Haskell에서의 동작 방법에 대한 포괄적인 설명.「기계화된 조립 라인」의 유추도 포함되어 있습니다.
- "Typeclassopedia"(원래 Brent Yorgey) - 모나드를 포함한 Haskell의 주요 활자 분류가 어떻게 상호 관련성이 있는지에 대한 자세한 설명입니다.
튜토리얼:
- "모나드의 주먹" (온라인 해스켈 교재 "Learn you a Haskell for Great Good!"에서): 예를 들어 펑터 및 적용 펑터 타입 클래스의 시작점부터의 모나드를 소개하는 장.
- "For a Few Monads More" - 두 번째 장에서는 자세한 내용과 예를 설명합니다.
Probability
마르코프 사슬의 모나드. - "Functors, Applications, And Monads In Pictures (Adidta Bhargava의 작품)" - 모나드에 대한 빠르고 유머러스하며 시각적인 튜토리얼입니다.
흥미로운 사례:
- 「UNIX pipes as IO monads」(Oleg Kiseyov) - Unix pipes as IO monads」(유닉스 파이프가 어떻게 효과적으로 monadic인지를 설명하는 짧은 에세이.
- Pro Scala: Web을 위한 Monadic Design Patterns (Gregory Meredith) - 모나드를 사용하여 Scala에서 웹 개발의 많은 측면을 개선하는 방법에 대한 미공개 전문 원고입니다.