보기 # 1 및 # 2는 일반적으로 올바르지 않습니다.
- 모든 종류의 데이터 유형은
* -> *
레이블로 작동 할 수 있으며 모나드는 그 이상입니다.
- (
IO
모나드를 제외하고) 모나드 내의 계산은 부정확하지 않습니다. 그것들은 단순히 부작용이있는 것으로 인식하는 계산을 나타내지 만 순수합니다.
이 두 가지 오해는 IO
모나드에 중점을 둔 것인데, 실제로는 약간 특별합니다.
가능한 경우 카테고리 이론에 들어 가지 않고 # 3에 대해 조금 자세히 설명하려고합니다.
표준 계산
함수형 프로그래밍 언어의 모든 계산은 소스 유형과 대상 유형이있는 함수로 볼 수 있습니다 f :: a -> b
. 함수에 인수가 둘 이상 있으면 카레 를 사용하여 인수를 하나의 인수 함수로 변환 할 수 있습니다 ( Haskell Wiki 참조 ). 우리가 값이 있다면 x :: a
(0 인수 함수를), 우리는의 인수를 취하는 함수로 변환 할 수 있습니다 단위 유형을 : (\_ -> x) :: () -> a
.
.
연산자를 사용하여 이러한 기능을 구성하여 더 복잡한 프로그램을 더 간단한 프로그램으로 만들 수 있습니다 . 예를 들어, 가지고 f :: a -> b
있고 g :: b -> c
우리가 얻는 다면 g . f :: a -> c
. 이것은 변환 된 값에도 적용됩니다. 우리가 x :: a
그것을 가지고 표현으로 변환하면, 우리는 얻습니다 f . ((\_ -> x) :: () -> a) :: () -> b
.
이 표현에는 다음과 같은 매우 중요한 속성이 있습니다.
- 우리는 매우 특별한 기능, 즉 각 유형에 대한 항등 함수
id :: a -> a
를 가지고 a
있습니다. 그것은 인 식별 요소 에 관하여 .
: f
모두에 동일 f . id
하고 id . f
.
- 함수 구성 연산자
.
는 연관되어 있습니다.
모나 딕 계산
특정 계산 범주를 선택하여 사용하고 그 결과에 단일 반환 값 이상의 것이 포함되어 있다고 가정합니다. 우리는 "더 많은 것"이 무엇을 의미하는지 지정하고 싶지 않으며 가능한 한 일반적인 것을 유지하고 싶습니다. 유형 - 가장 일반적인 방법은 표현하기 위해 "뭔가 더"유형 기능으로 대표되는 m
종류의 * -> *
(즉, 또 다른 한 형식 변환). 따라서 우리가 작업하고자하는 각 계산 범주에 대해 몇 가지 type 함수가 m :: * -> *
있습니다. (하스켈에서, m
이고 []
, IO
, Maybe
, 등) 및 분류 의지 유형의 모든 기능을 포함 a -> m b
.
이제 기본 사례에서와 같은 방식으로 이러한 범주의 함수를 사용하려고합니다. 우리는 이러한 기능을 구성 할 수 있기를 원하며, 구성이 연관되기를 원하며 정체성을 원합니다. 우리는 필요합니다 :
- (현실을 부르 자 연산자를하려면
<=<
그 기능을 구성하는) f :: a -> m b
과 g :: b -> m c
같은 무언가로 g <=< f :: a -> m c
. 그리고 그것은 연관 적이어야합니다.
- 각 유형에 대해 일부 신원 기능을 갖기 위해 그것을 호출합시다
return
. 우리는 또한 원하는 f <=< return
과 동일 f
과 동일 return <=< f
.
모든이 m :: * -> *
있는 우리는 기능을 가지고 return
와 <=<
불리며 모나드 . 기본 경우와 같이 더 간단한 계산을 통해 복잡한 계산을 만들 수 있지만 이제는 반환 값 유형이로 변환됩니다 m
.
(사실, 난 약간 용어 학대 범주를 여기에. 우리는 우리가이 법을 따르는 알고 후에 만 카테고리 우리의 건설 호출 할 수있는 범주 이론의 의미에서.)
하스켈의 모나드
하스켈 (그리고 다른 기능 언어)에서 우리는 대부분없는 유형의 기능, 가치와 함께 작동 () -> a
. 따라서 <=<
각 모나드에 대해 정의하는 대신 함수를 정의합니다 (>>=) :: m a -> (a -> m b) -> m b
. 그러한 대안 적 정의는 동등하며, 우리는를 >>=
사용하여 표현 <=<
하거나 그 반대로 표현할 수 있습니다 (운동으로 시도하거나 출처를보십시오 ). 원칙은 현재 명확하지 않지만 동일하게 유지됩니다. 결과는 항상 유형 m a
이며 유형의 함수를 구성합니다 a -> m b
.
각 우리가 만드는 모나드를 들어, 우리는 것을 확인하는 것을 잊지합니다 return
및 <=<
연관성 및 왼쪽 / 오른쪽 정체성 : 우리가 필요한 특성을 가지고있다. 표현 사용 return
하고 >>=
그들은이라고 모나드 법 .
예-목록
우리가하기로 선택 m
하면 []
, 우리는 유형의 함수 범주를 얻는다 a -> [b]
. 이러한 함수는 비 결정적 계산을 나타내며 그 결과는 하나 이상의 값일 수 있지만 값은 없습니다. 이것은 소위 list monad를 발생 시킵니다. 조성물 f :: a -> [b]
및 g :: b -> [c]
다음 방법 : g <=< f :: a -> [c]
수단은 모든 가능한 유형의 결과를 계산은 [b]
적용 g
그들 각각에, 그리고 하나의리스트에있는 모든 결과를 수집한다. 하스켈로 표현
return :: a -> [a]
return x = [x]
(<=<) :: (b -> [c]) -> (a -> [b]) -> (a -> [c])
g (<=<) f = concat . map g . f
또는 사용 >>=
(>>=) :: [a] -> (a -> [b]) -> [b]
x >>= f = concat (map f x)
이 예제에서 리턴 유형은 [a]
type의 값을 포함하지 않았을 수 있습니다 a
. 실제로, 반환 유형에 이러한 값이 있어야한다는 모나드에 대한 요구 사항은 없습니다. 일부 모나드는 항상 (와 같 IO
거나 State
) 있지만 일부는 []
나 같지 않습니다 Maybe
.
IO 모나드
앞서 언급했듯이 IO
모나드는 다소 특별합니다. 유형 값은 프로그램 환경과 상호 작용하여 구성된 유형 값을IO a
의미 합니다. 따라서 다른 모나드와 달리 순수한 구성을 사용하여 유형의 값을 설명 할 수는 없습니다 . 다음 은 환경과 상호 작용하는 계산을 구별하는 태그 또는 레이블입니다. 이것은 뷰 # 1과 # 2가 올바른 유일한 경우입니다.a
IO a
IO
위해 IO
모나드 :
- 구성
f :: a -> IO b
및 g :: b -> IO c
의미 : f
환경과 상호 작용하는 계산 후g
값을 사용하여 계산하고 환경과 상호 작용하는 결과를 계산합니다.
return
IO
"태그"를 값에 추가하기 만하면됩니다 (환경을 그대로 유지하여 결과를 "계산"합니다).
- 모나드 법칙 (연관성, 동일성)은 컴파일러에 의해 보장됩니다.
몇 가지 참고 사항 :
- 모나드 계산은 항상 결과 유형을 가지므로 모나드
m a
에서 "탈출"하는 방법은 없습니다 IO
. 의미는 다음과 같습니다. 일단 계산이 환경과 상호 작용하면 그렇지 않은 계산을 구성 할 수 없습니다.
- 함수형 프로그래머가 순수한 방법으로 무언가를 만드는 방법을 모른다면, ( 마지막 수단으로)
IO
모나드 내에서 상태 저장 계산을 통해 작업을 프로그래밍 할 수 있습니다 . 이것이 IO
종종 프로그래머의 sin bin 이라고 불리는 이유 입니다 .
- 불완전한 세계 (기능 프로그래밍의 의미에서)에서 값을 읽으면 사용자의 입력 소비와 같이 환경도 변경 될 수 있습니다. 따라서 같은 함수
getChar
의 결과 유형은이어야합니다 IO something
.