2017-11-28 21 views
2

IO [[Char]]IO()을 바인딩해도 괜찮지 만 MaybeIO으로 바인딩 할 수는 없습니다. 누군가이 완화 작용이 나쁜 디자인으로 이어질 수있는 예를 들어 줄 수 있습니까? Monad의 다형성 유형에서 자유가 허용되는 이유는 무엇입니까?같은 모나드 타입 만이`>> '연산자로 연결되는 것을 허용하는 논리는 무엇입니까?

+5

typeclass 인스턴스가 실제로 지원하는 연산 만 사용할 수 있습니다. 'Monad'의 인스턴스는'(>> =) :: m a -> (a -> m b) -> m b'만을 제공합니다. 즉, 전체적으로 동일한'm'을 제한적으로 요구합니다. 임의의 "bind over anything"연산이 있다는 의미있는 의미를 알 수 있다면 꼭 모든 인스턴스를 typeclass로 지정하고 알고있는만큼의 인스턴스를 생성 할 수 있습니다. '(>> =) :: m a -> (a -> n b) -> n b'와 같은 클래스는 소비자를 필요로하지 않지만 구현자를 위해 현명하게 만족시키는 것은 거의 불가능합니다. –

+1

'Monad' 타입 클래스 뒤에있는 이론은'm'이 같은 펑터가되도록 요구합니다; 이 속성은 IO를 처리하기위한 기초로 적합하게 만드는 요소입니다. 다른 유형으로 전환하여'IO'에서 탈출 할 수 없습니다. – chepner

+1

'아마도'아마도'IO'와 어떻게 묶을 수 있을까요? 'IO' 모나드는 상태를 변경시키지 않으며 * 상태를 변경하는 * 방법을 설명합니다. –

답변

7

많은 이론적 인 이유가 있습니다. "그게 뭔지는 Monad이 아닙니다." 그러나 잠시 그 ​​단계에서 벗어나 구현 세부 사항을 살펴 보겠습니다.

먼저 꺼짐 - Monad은 마법이 아닙니다. 그것은 단지 표준 타입 클래스입니다. Monad의 인스턴스는 누군가가 하나를 작성할 때만 생성됩니다.

해당 인스턴스를 작성하는 것은 (>>)의 작동 방식을 정의합니다. 일반적으로 (>>=)이라는 용어로 암시 적으로 기본 정의를 통해 수행되지만, 이는 단지 (>>=)이 더 일반적인 연산자라는 증거이며, 쓰기는 (>>)과 동일한 결정을 내릴 것을 요구합니다.

더 일반적인 유형의 다른 연산자를 사용하는 경우 두 가지 질문에 답해야합니다. 첫째, 유형은 무엇입니까? 둘째, 구현을 제공하는 방법에 대해 어떻게 생각하십니까? 질문에서 원하는 유형이 무엇인지 분명하지 않습니다. 다음 중 하나 일 것입니다 :

class Poly1 m n where 
    (>>) :: m a -> n b -> m b 

class Poly2 m n where 
    (>>) :: m a -> n b -> n b 

class Poly3 m n o | m n -> o where 
    (>>) :: m a -> n b -> o b 

이 모두를 구현할 수 있습니다. 그러나 실제적으로 사용하기 위해서는 두 가지 중요한 요소를 잃게됩니다.

  1. 함께 사용하려는 모든 유형 쌍에 대한 인스턴스를 작성해야합니다. 이것은 각 유형에 대한 인스턴스보다 훨씬 복잡한 작업입니다. 뭔가 약 nn^2.
  2. 예측 가능성이 떨어집니다. 수술은 무엇입니까 합니까? 이론과 실습이 교차하는 곳입니다. Monad의 이론은 작업에 많은 제한을 가하고 있습니다. 이러한 제한을 "모나드 법"이라고합니다. 그것들은 Haskell에서 검증 할 수있는 능력을 넘어서는 것이지만, 그것들을 따르지 않는 어떤 Monad 인스턴스는 버그가있는 것으로 간주됩니다. 최종 결과는 Monad 작업이 수행하는 작업과 수행하지 않는 작업에 대한 직관을 신속하게 구축 할 수 있다는 것입니다. 관련된 모든 유형의 세부 사항을 조회하지 않고도 사용할 수 있습니다. 특성에 대한 지식을 알고 있기 때문입니다. 제가 제안한 가능한 클래스 중 어느 것도 당신에게 그런 종류의 보장을주지 않습니다. 당신은 그들이 무엇을하는지 전혀 모른다.
0

는 내가 제대로 질문을 이해 모르겠지만, 그것은 당신이 []IO을 구성 할 수 같은 의미에서 IO 또는 []으로 Maybe를 구성 할 확실히 가능합니다. 당신이 :t를 사용 GHCI의 형식을 선택하면 예를 들어

getContents >>= return . lines 

당신에게 IO [String]을 제공합니다.당신이

  >>= return . map Text.Read.readMaybe 

를 추가 할 경우 당신은 IO, []Maybe의 구성입니다 IO [Maybe a]의 유형을 얻을.

  >>= return . Data.Maybe.catMaybes 

으로 전달하여 IO [a]으로 플랫화 할 수 있습니다. 그런 다음 구문 분석 된 유효한 입력 행의 목록을 다시 평평하게하고 출력을 계산하는 함수에 전달할 수 있습니다.

입력하여 프로그램을 함께

import Text.Read (readMaybe) 
import Data.Maybe (catMaybes) 

main :: IO() 
main = getContents >>=     -- IO String 
     return . lines >>=     -- IO [String] 
     return . map readMaybe >>=   -- IO [Maybe Int] 
     return . catMaybes >>=    -- IO [Int] 
     return . (sum :: [Int] -> Int) >>= -- IO Int 
     print        -- IO() 

를 이러는 :

1 

2 
Ignore this! 
3 

인쇄 6.

또한 IO (Maybe [String]) 작업 할 수있을 것이다하는 Maybe [IO String]

당신은뿐만 아니라 >>이 작업을 수행 할 수 있습니다. 고안된 예 : getContents >> (return . Just) False은 입력을 읽고 무시하고 IO (Maybe Bool)을 돌려줍니다.