문제

나는 모나드에 대해 배우고 몇 가지 질문이 있습니다.

이것은 내가 지금있는 곳입니다. 내가 틀린 곳을 바로 잡아주세요.

  • 그만큼 >>= 기호는 디픽스 연산자입니다. Infix 연산자는 두 개의 인수 (왼쪽 및 오른쪽)를 취하고 값을 반환하는 기능입니다.

  • 그만큼 >>= 기호를 바인드 연산자라고하며 서명이 있습니다 Monad m => m t -> (t -> m u) -> m u. 그러나이 유형은 여기에 줄을서는 것 같습니다. 우리는 유형의 가치를 얻습니다 m t 그리고 두 번째 인수는 t. (점들을 연결하는 방법이 모르겠습니다.)

  • 이것은 결합 함수가 어떻게 든 제거 할 수 있음을 의미해야합니다. m ~로부터 m t 얻기 위해 t 그리고 그것을 함수로 전달하십시오.

내 질문은 다음과 같습니다.

  • 제거하는 능력입니다 m ~에서 m t 그러한 바인드 연산자 안에서만 가능한 것. 이 바인딩 연산자에게 특별한 특권이나 무언가가 있습니까?

  • 상태 변경과 어떤 관련이 있습니까? 모나드의 목표는 프로그램의 나머지 부분에서 격리되도록 부작용을 '포장'하는 것임을 이해합니다. 그러나 이것에서 바인드 연산자의 역할은 무엇입니까?

도움이 되었습니까?

해결책

그러한 바인드 연산자 내부에서만 가능한 'M'에서 'm'을 제거하는 능력입니다. 이 바인딩 연산자에게 특별한 특권이나 무언가가 있습니까?

BIND는 특별한 경우에는 그렇지 않지만 일반적으로 Monads 데이터 유형과 동일한 모듈로 정의됩니다. 따라서 모듈에서 내보내지 않은 세부 사항에 대해 알고있을 수 있습니다. 일반적인 경우는 모듈이 데이터 유형을 내보내지 만 내부 구조 유형에 대한 생성자 또는 기타 세부 사항은 아닙니다. 그런 다음 모듈을 사용하는 코드의 경우 데이터 유형의 내부 작업이 보이지 않으며 코드 가이 유형의 값을 직접 수정할 수 없습니다.

예를 들어 일부 바인드 연산자와 같이 모듈 내부에서 정의 된 해당 기능에 반대합니다. >>=, 정의 된 모듈에서 좋아하는 모든 것에 액세스 할 수 있습니다. 따라서 이러한 기능은 "외부"기능을 수행 할 수 없습니다.

특별한 경우입니다 IO 모나드는 모듈에 의해 정의되지 않았지만 런타임 시스템/컴파일러에 내장되어 있기 때문에. 여기서 컴파일러는 구현의 내부 세부 사항에 대해 알고 있으며 다음과 같은 기능을 노출시킵니다. IO'에스 >>=. 이러한 기능의 구현은 실제로 "프로그램 외부"이기 때문에 특별히 특권이 있지만, 이것은 특별한 경우이며,이 사실은 Haskell 내에서 관찰 할 수 없어야합니다.

상태 변경과 어떤 관련이 있습니까? 모나드의 목표는 프로그램의 나머지 부분에서 격리되도록 부작용을 '포장'하는 것임을 이해합니다. 그러나 이것에서 바인드 연산자의 역할은 무엇입니까?

상태 변경과 관련이있을 필요는 없습니다. 이것은 Moands로 처리 할 수있는 한 가지 문제 일뿐입니다. 그만큼 IO Monad는 특정 순서로 IO를 실행하는 데 사용되지만 일반적으로 Monads는 기능을 결합하는 방법 일뿐입니다.

일반적으로 모나드 (특히 바인드 함수)는 특정 함수가 더 큰 기능으로 함께 구성되어야하는 방식을 정의합니다. 기능을 결합하는이 방법은 모나드에서 추상화됩니다. 이 결합이 정확히 어떻게 작동하는지 또는 그러한 방식으로 기능을 결합하려는 이유는 중요하지 않습니다. Monad는 특정한 방식으로 특정 기능을 결합하는 방법을 지정합니다. (또한보십시오 이 "C# 프로그래머를위한 모나드"답변 기본적으로 예제와 함께 몇 번 반복합니다.)

다른 팁

그러한 바인드 연산자 내부에서만 가능한 'M'에서 'm'을 제거하는 능력입니다.

글쎄, 유형의 유형이 지정 하듯이 바인드 연산자 내부에서는 확실히 가능합니다.

(>>=) :: m a -> (a -> m b) -> m b

모나드의 '실행'기능은 일반적으로이를 수행 할 수 있습니다 (계산에서 순수한 가치를 반환).

Monads의 목표는 프로그램의 나머지 부분에서 격리되도록 부작용을 '랩'하는 것입니다.

흠. 아니요, Monads는 계산 개념을 모델링하겠습니다. 부작용 계산은 상태, 역 추적, 연속, 동시성, 트랜잭션, 선택적 결과, 임의 결과, 역전 가능한 상태, 비 결정적 ... 모두와 같은 개념 중 하나 일뿐입니다. 모나드로 설명 할 수 있습니다

IO 모나드는 당신이 말하는 것입니다. 그것은 약간 이상한 모나드입니다 - 그것은 세계 상태에 대한 추상적 인 변화 시퀀스를 생성 한 다음 런타임에 의해 평가됩니다. BIND는 IO 모나드에서 올바른 순서로 사물을 시퀀싱 할 수있게 해줍니다. 그런 다음 컴파일러는이 모든 시퀀싱 된 세계 수정 작업을 기계 상태를 변경하는 필수 코드로 변환합니다.

그것은 일반적으로 모나드가 아니라 IO 모나드에 매우 구체적입니다.

다음은 유형 클래스의 정의입니다 Monad.

class  Monad m  where

    (>>=)       :: forall a b. m a -> (a -> m b) -> m b
    (>>)        :: forall a b. m a -> m b -> m b
    return      :: a -> m a
    fail        :: String -> m a

    m >> k      = m >>= \_ -> k
    fail s      = error s

유형 클래스의 각 유형 인스턴스 Monad 자체를 정의합니다 >>= 기능. 다음은 Type-Instance의 예입니다 Maybe:

instance  Monad Maybe  where

    (Just x) >>= k      = k x
    Nothing  >>= _      = Nothing

    (Just _) >>  k      = k
    Nothing  >>  _      = Nothing

    return              = Just
    fail _              = Nothing

우리가 볼 수 있듯이 Maybe 버전 >>= 이해하기 위해 특별히 정의되어 있습니다 Maybe 유형-인스턴스, 그리고 그것은 법적으로 액세스 할 수있는 장소에서 정의되기 때문입니다. data Maybe a 데이터 생성자 Nothing 그리고 Just a,, Maybe 버전 >>= 풀릴 수 있습니다 ain Maybe a 그리고 그들을 통과하십시오.

예를 통해 작업하기 위해 다음을 수행 할 수 있습니다.

x :: Maybe Integer
x = do a <- Just 5
       b <- Just (a + 1)
       return b

퇴직하지 않으면 다음은 다음과 같습니다.

x :: Maybe Integer
x = Just 5        >>= \a ->
    Just (a + 1)  >>= \b ->
    Just b

다음과 같이 평가합니다.

  =                  (\a ->
    Just (a + 1)  >>= \b ->
    Just b) 5

  = Just (5 + 1)  >>= \b ->
    Just b

  =                  (\b ->
    Just b) (5 + 1)

  = Just (5 + 1)

  = Just 6

유형은 재미있게 줄어 듭니다. 방법은 다음과 같습니다.

모나드는 또한 함수이라는 것을 기억하십시오. 다음 함수는 모든 기능에 대해 정의됩니다.

fmap :: (Functor f) => (a -> b) -> f a -> f b

이제 질문 : 이러한 유형이 실제로 일치합니까? 글쎄, 그렇습니다. 기능이 주어졌습니다 a 에게 b, 그렇다면 환경이 있다면 f 그곳에서 a 이용 가능하고 환경이 있습니다 f 그곳에서 b 사용할 수 있습니다.

음절과 유사하게 :

(Functor Socrates) => (Man -> Mortal) -> Socrates Man -> Socrates Mortal

이제 아시다시피, 모나드는 바인딩 앤 리턴이 장착 된 기능자입니다.

return :: (Monad m) => a -> m a
(=<<) :: (Monad m) => (a -> m b) -> m a -> m b

동등하게, 반품 및 가입이 장착 된 untictor라는 것을 알지 못할 수도 있습니다.

join :: (Monad m) => m (m a) -> m a

우리가 어떻게 벗겨 지는지보십시오 m. 모나드와 함께 m, 당신은 항상 얻을 수는 없습니다 m a 에게 a, 그러나 당신은 항상 얻을 수 있습니다 m (m a) 에게 m a.

이제 첫 번째 논쟁을보십시오 (=<<). 유형의 함수입니다 (a -> m b). 그 기능을 전달할 때 어떻게됩니까? fmap? 당신은 얻습니다 m a -> m (m b). 그래서, "매핑" m a 기능으로 a -> m b 당신을 준다 m (m b). 이것은 논쟁의 유형과 똑같습니다. join. 이것은 우연의 일치가 아닙니다. "Bind"의 합리적인 구현은 다음과 같습니다.

(>>=) :: m a -> (a -> m b) -> m b
x >>= f = join (fmap f x)

실제로 바인드와 조인은 서로의 관점에서 정의 될 수 있습니다.

join = (>>= id)

나는 당신이 읽는 것이 좋습니다 (http://blog.sigfpe.com/2006/08/you-hould-have-invented-monads-and.html). 그것은 모나드가 존재하는 완벽한 상식적인 이유를 제공합니다.

모나드의 목표는 프로그램의 나머지 부분에서 격리되도록 부작용을 '포장'하는 것임을 이해합니다.

실제로 그것보다 조금 더 미묘합니다. 모나드는 우리가 매우 일반적인 방식으로 시퀀싱을 모델링 할 수있게 해줍니다. 도메인 전문가와 대화 할 때 종종 "우리는 X를 시도합니다. 그러면 우리는 Y를 시도하고 그것이 작동하지 않으면 z를 시도합니다"라고 말합니다. 기존 언어로 그런 것을 구현하려고 할 때는 그것이 적합하지 않다는 것을 알게되므로 "then"이라는 단어의 도메인 전문가가 의미하는 모든 것을 다루기 위해 많은 추가 코드를 작성해야합니다.

Haskell에서는 바인드 연산자로 번역 된 "그런 다음"이있는 모나드로 이것을 구현할 수 있습니다. 예를 들어, 한 번은 특정 규칙에 따라 수영장에서 품목을 할당 해야하는 프로그램을 작성했습니다. Case 1의 경우 수영장 X에서 가져갔습니다. 비어 있으면 수영장 Y로 이동했습니다. 케이스 2의 경우 수영장 Y에서 곧바로 가져 가야했습니다. Pool X 또는 Y에서 가장 최근에 사용 된 최소한.

case c of
   1: do {try poolX; try poolY}
   2: try poolY
   3: try $ lru [poolX, poolY]

아주 잘 작동했습니다.

물론 여기에는 기존의 시퀀싱 모델이 포함됩니다. IO Monad는 다른 모든 프로그래밍 언어가 가지고있는 모델입니다. Haskell에서는 환경의 일부보다는 명백한 선택입니다. St Monad는 IO의 메모리 돌연변이를 제공하지만 실제 입력 및 출력은 없습니다. 반면에 State Monad는 귀하의 상태를 명명 된 유형의 단일 값으로 제한 할 수 있습니다.

정말로 뇌 굽힘에 대해서는 참조하십시오 이 블로그 게시물 후진 주 모나드에 대해. 상태는 "실행"과 반대 방향으로 전파됩니다. 이것을 하나의 명령을 실행 한 주 모나드와 다음을 수행하는 것으로 생각되면, "put"은 주 값을 전적으로 "get"로 거꾸로 보냅니다. 뭐 실제로 발생하는 것은 역설이없는 경우에만 종료되는 상호 재귀 함수가 설정됩니다. 나는 그런 모나드를 어디에서 사용 해야할지 잘 모르겠지만, 모나드가 계산 모델이라는 점을 보여줍니다.

준비가되지 않았다면 바인드를 과부하 가능한 세미콜론으로 생각하십시오. 그것은 당신에게 꽤 먼 길을 얻습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top