수색…


소개

모나드는 조합 가능한 액션의 데이터 유형입니다. Monad 는 값이 그러한 액션을 나타내는 유형 생성자의 클래스입니다. 아마도 IO 은 가장 인식할만한 것입니다. IO a a 값은 "현실 세계에서 값을 검색하는 a "입니다.

우리는 타입 생성자라고 m (예 : [] 또는 Maybe 이 생길 경우) 모나드를 형성하는 instance Monad m 행동의 구성에 대한 특정 법률을 만족. 그러면 우리는 "결과가 유형 a 인 행위"라고 ma 수 있습니다.

아마 모나드

Maybe 유사 - 하늘의 값을 나타내는 데 사용됩니다 null 다른 언어를. 일반적으로 어떤 방식 으로든 실패 할 수있는 함수의 출력 유형으로 사용됩니다.

다음 기능을 고려하십시오.

halve :: Int -> Maybe Int
halve x
  | even x = Just (x `div` 2)
  | odd x  = Nothing

생각 halve 온 따라 조치로 Int 이 홀수 인 경우 실패 정수를 반으로하려고합니다.

정수를 세 번 halve 방법은 무엇입니까?

takeOneEighth :: Int -> Maybe Int            -- (after you read the 'do' sub-section:)
takeOneEighth x =                
  case halve x of                               --  do {
    Nothing -> Nothing
    Just oneHalf ->                             --     oneHalf    <- halve x
      case halve oneHalf of
        Nothing -> Nothing
        Just oneQuarter ->                      --     oneQuarter <- halve oneHalf
          case halve oneQuarter of
            Nothing -> Nothing                  --     oneEighth  <- halve oneQuarter
            Just oneEighth ->                         
              Just oneEighth                    --     return oneEighth }
  • takeOneEighth서열이다 halve 서로 연결하는 단계.
  • 경우 halve 단계가 실패, 우리는 전체를 구성 할 takeOneEighth 실패 할 수 있습니다.
  • halve 단계가 성공하면 그 결과를 앞당기 고 싶습니다.

instance Monad Maybe where
  -- (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
  Nothing >>= f  = Nothing                            -- infixl 1 >>=
  Just x  >>= f  = Just (f x)                         -- also, f =<< m = m >>= f
  
  -- return :: a -> Maybe a
  return x       = Just x

이제 우리는 다음과 같이 쓸 수 있습니다.

takeOneEighth :: Int -> Maybe Int
takeOneEighth x = halve x >>= halve >>= halve             -- or,
    -- return x >>= halve >>= halve >>= halve             -- which is parsed as
    -- (((return x) >>= halve) >>= halve) >>= halve       -- which can also be written as
    -- (halve =<<) . (halve =<<) . (halve =<<) $ return x    -- or, equivalently, as
    --  halve <=<     halve <=<     halve      $        x

클라이슬리에 조성 <=<(g <=< f) x = g =<< fx 또는 이와 동등하게 (f >=> g) x = fx >>= g 됩니다. 그것으로 위의 정의는

takeOneEighth :: Int -> Maybe Int
takeOneEighth = halve <=< halve <=< halve               -- infixr 1 <=<
        -- or, equivalently,                    
        --      halve >=> halve >=> halve               -- infixr 1 >=>    

Monad typeclass의 인스턴스 인 모든 모나드에 따라야하는 세 가지 모나드 법칙이 있습니다.

1.  return x >>= f  =  f x
2.    m >>= return  =  m
3. (m >>= g) >>= h  =  m >>= (\y -> g y >>= h)

여기서 m 은 모나드이고, fa -> mb 이고 gb -> mc 유형이다.

또는 이와 동등하게, 위에 정의 된 >=> Kleisli 합성 연산자를 사용합니다.

1.    return >=> g  =  g                    -- do { y <- return x ; g y } == g x
2.    f >=> return  =  f                    -- do { y <- f x ; return y } == f x
3. (f >=> g) >=> h  =  f >=> (g >=> h)      -- do { z <- do { y <- f x; g y } ; h z }
                                            --  == do { y <- f x ; do { z <- g y; h z } }

이 법칙을 따르면 모나드에 대한 추론이 훨씬 쉬워집니다. 왜냐하면 모나드 함수를 사용하고 다른 모나드와 유사한 합리적인 방법으로 동작하도록 보장하기 때문입니다.

Maybe 모나드가 세 모나드 법칙에 복종하는지 확인합시다.

  1. 왼쪽 정체성 법칙 - return x >>= f = fx
return z >>= f 
= (Just z) >>= f 
= f z
  1. 올바른 정체성 법칙 - m >>= return = m
  • Just 데이터 생성자
Just z >>= return
= return z
= Just z  
  • 데이터 생성자가 Nothing
Nothing >>= return
= Nothing 
  1. 결합 법칙 - (m >>= f) >>= g = m >>= (\x -> fx >>= g)
  • Just 데이터 생성자
-- Left-hand side
((Just z) >>= f) >>= g
= f z >>= g

-- Right-hand side
(Just z) >>= (\x -> f x >>= g)
(\x -> f x >>= g) z
= f z >>= g
  • 데이터 생성자가 Nothing
-- Left-hand side
(Nothing >>= f) >>= g
= Nothing >>= g
= Nothing

-- Right-hand side
Nothing >>= (\x -> f x >>= g)
= Nothing

IO 모나드

IO a 유형의 표현식에서 a 유형의 값을 가져올 수있는 방법이 없습니다. 이것은 실제로 모나드가 IO 를 모델링하는 데 사용되는 이유 중 상당 부분입니다.

유형 IO a 의 표현식은 실제 세계와 상호 작용할 수있는 조치를 나타내는 것으로 간주 될 수 있으며, 실행되면 유형이 a 가 될 것입니다. 예를 들어, 함수 getLine :: IO String 전주곡에서은 아래 것을 의미하지 않는다 getLine 내가 추출 할 수있는 몇 가지 특정 문자열이 -는 것을 의미 getLine 표준 입력에서 라인을 가져 오는 작업을 나타냅니다.

놀랍지 않게도, main :: IO () 는 Haskell 프로그램이 실제 세계와 상호 작용하는 계산 / 동작을 표현하기 때문에 그렇습니다.

IO 이 모나드이기 때문에 타입 IO a 타입의 표현에 할 있는 일 :

  • 첫 번째 액션을 실행하는 새 액션을 생성하기 위해 (>>) 를 사용하여 두 액션을 시퀀싱하고, 생성 한 모든 값을 삭제 한 다음 두 번째 액션을 실행합니다.

      -- print the lines "Hello" then "World" to stdout
      putStrLn "Hello" >> putStrLn "World"
    
  • 때로는 첫 번째 작업에서 생성 된 값을 삭제하지 않으려는 경우가 있습니다. 실제로 두 번째 작업으로 가져 오는 것이 좋습니다. 이를 위해 >>= 합니다. IO , (>>=) :: IO a -> (a -> IO b) -> IO b 유형을 갖습니다.

     -- get a line from stdin and print it back out
     getLine >>= putStrLn
    
  • 정상적인 가치를 취하고 행동으로 변환하면 즉시 주어진 값을 반환합니다. 이 기능은 do notation을 사용하기 전까지는 덜 분명합니다.

     -- make an action that just returns 5
     return 5
    

하스켈 위키에서 IO 모나드에 대한 자세한 내용이 나와 있습니다 .

목록 모나드

목록은 모나드를 형성합니다. 그들은 이것과 같은 모나드 인스턴스화를 가지고 있습니다 :

instance Monad [] where 
  return x = [x]
  xs >>= f = concat (map f xs)               

계산에서 비 결정론을 에뮬레이션하기 위해 그것들을 사용할 수 있습니다. 우리가 사용하는 경우 xs >>= f , 함수 f :: a -> [b] 리스트에 매핑된다 xs 의 각 애플리케이션의 결과리스트의 목록을 획득하는 f 의 각 요소 위에 xs , 모든리스트 결과는 모든 결과의 하나의 목록으로 연결됩니다. 예를 들어 do notation을 사용하여 두 개의 비 결정적 숫자의 합계를 계산합니다.이 합계는 두 개의 목록에있는 모든 정수 쌍의 합계 목록으로 표현됩니다. 각 목록은 비 결정적 숫자의 가능한 모든 값을 나타냅니다.

sumnd xs ys = do
  x <- xs
  y <- ys
  return (x + y)

또는 이와 동등하게, Control.Monad 에서 liftM2 를 사용합니다.

sumnd = liftM2 (+)

우리는 얻는다 :

> sumnd [1,2,3] [0,10]
[1,11,2,12,3,13]

적용 대상 서브 클래스로서의 모나드

GHC 7.10로, Applicative 의 슈퍼 클래스입니다 Monad (즉,있는 모든 유형의 Monad 또한해야 Applicative ). Applicative ( pure , <*> )의 모든 메소드는 Monad 의 메소드 ( return , >>= )로 구현 될 수 있습니다.

pure 하고 return 하는 것이 동등한 목적을 제공한다는 것은 명백하므로 pure = return . <*> 대한 정의는 너무 명확합니다.

mf <*> mx = do { f <- mf; x <- mx; return (f x) }                 
       -- = mf >>= (\f -> mx >>= (\x -> return (f x)))
       -- = [r   | f <- mf, x <- mx, r <- return (f x)]   -- with MonadComprehensions
       -- = [f x | f <- mf, x <- mx]                   

이 함수는 표준 라이브러리에서 ap 로 정의됩니다.

따라서 유형에 대한 Monad 의 인스턴스를 이미 정의한 경우 효과적으로 정의를 통해 "무료"로 Applicative 의 인스턴스를 가져올 수 있습니다

instance Applicative < type > where
    pure  = return
    (<*>) = ap

모나드 법칙과 마찬가지로 이러한 동등성은 적용되지 않지만 개발자는 항상 동등한 상태를 유지해야합니다.

모나드 계산에서 값을 추출하는 일반적인 방법이 없습니다.

값을 액션으로 래핑하고 한 계산의 결과를 다른 것으로 전달할 수 있습니다.

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

그러나 Monad의 정의는 Monad m => ma -> a 형식의 함수의 존재를 보장하지 않습니다.

즉, 일반적 으로 계산에서 값을 추출 할 방법이 없습니다 (예 : "unwrap"). 다음과 같은 경우가 많습니다.

extract :: Maybe a -> a
extract (Just x) = x          -- Sure, this works, but...
extract Nothing  = undefined  -- We can’t extract a value from failure.

특히, IO a -> a 함수가 없기 때문에 초보자를 혼란스럽게합니다. 이 예제를 참조하십시오.

표기법

do -notation은 모나드를위한 통사론이다. 다음은 규칙입니다.

do x <- mx                               do x <- mx
   y <- my       is equivalent to           do y <- my
   ...                                         ...
do let a = b                             let a = b in
   ...           is equivalent to          do ...
do m                                     m >> (
   e             is equivalent to          e)
do x <- m                                m >>= (\x ->
   e             is equivalent to          e)
do m             is equivalent to        m

예를 들어, 다음 정의는 동일합니다.

example :: IO Integer
example =
  putStrLn "What's your name?" >> (
    getLine >>= (\name ->
      putStrLn ("Hello, " ++ name ++ ".") >> (
        putStrLn "What should we return?" >> (
          getLine >>= (\line ->
            let n = (read line :: Integer) in
              return (n + n))))))

example :: IO Integer
example = do
  putStrLn "What's your name?"
  name <- getLine
  putStrLn ("Hello, " ++ name ++ ".")
  putStrLn "What should we return?"
  line <- getLine
  let n = (read line :: Integer)
  return (n + n)

Monad의 정의

class Monad m where
    return :: a -> m a
    (>>=) :: m a -> (a -> m b) -> m b

모나드를 다루기위한 가장 중요한 함수는 바인드 연산자 >>= :

(>>=) :: m a -> (a -> m b) -> m b
  • 생각 ma 의 "와 행동으로 결과". a
  • a -> mb" a 매개 변수에 따라 b 결과가있는 동작" 이라고 생각하십시오.

>>= 첫 번째 작업의 결과를 두 번째 작업으로 파이핑하여 두 작업을 함께 처리합니다.

Monad 가 정의한 다른 함수는 다음과 같습니다.

return :: a -> m a

그 이름은 불행한 일입니다.이 return 은 명령형 프로그래밍 언어에서 발견 된 return 키워드와 아무런 관련이 없습니다.

return x 는 그 결과로 x 를 산출하는 사소한 행동입니다. (그것은 다음과 같은 의미 에서 사소합니다 :)

return x >>= f       ≡  f x     --  “left identity” monad law
       x >>= return  ≡  x       -- “right identity” monad law


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow