Подтвердить что ты не робот

Каковы определения для > >= и возврата для монады IO?

Увидев, как монады списка и Maybe определены, мне, естественно, стало любопытно, как  операции >>= и return определены для монады IO.

4b9b3361

Ответ 1

Для IO нет конкретной реализации; это абстрактный тип, с точной реализацией слева от undefined по Haskell Report. В самом деле, ничто не останавливает реализацию, реализующую IO и ее экземпляр Monad как примитивы компилятора, без реализации Haskell вообще.

В принципе, Monad используется как интерфейс к IO, который сам не может быть реализован в чистом Haskell. Вероятно, все, что вам нужно знать на этом этапе, и погружение в детали реализации, скорее всего, просто смутит, а не даст понимание.

Тем не менее, если вы посмотрите на исходный код GHC, вы обнаружите, что он представляет IO a как функцию, похожую на State# RealWorld -> (# State# RealWorld, a #) (используя unboxed tuple как возвращаемый тип), но это вводит в заблуждение; это деталь реализации, и эти значения State# RealWorld фактически не существуют во время выполнения. IO не является государственной монадой, 1 в теории или на практике.

Вместо этого GHC использует нечистые примитивы для реализации этих операций ввода-вывода; значения State# RealWorld "только для того, чтобы остановить операторы переупорядочения компилятора, введя зависимости данных от одного оператора к следующему.

Но если вы действительно хотите увидеть реализацию GHC return и (>>=), вот они:

returnIO :: a -> IO a
returnIO x = IO $ \ s -> (# s, x #)

bindIO :: IO a -> (a -> IO b) -> IO b
bindIO (IO m) k = IO $ \ s -> case m s of (# new_s, a #) -> unIO (k a) new_s

где unIO просто разворачивает функцию из конструктора IO.

Важно отметить, что IO a представляет описание нечистого вычисления, которое может быть выполнено для создания значения типа a. Тот факт, что существует способ получить значения из внутреннего представления GHC IO, не означает, что это выполняется в целом или что вы можете сделать такую ​​вещь для всех монадов. Это исключительно детализация со стороны GHC.

1 Государственная монада - монада, используемая для доступа и изменения состояния через серию вычислений; он представлен как s -> (a, s) (где s - тип состояния), который очень похож на тип GHC использует для IO, таким образом, путаницу.

Ответ 2

Вы будете разочарованы, но монада >>= in IO не интересна. Чтобы указать источник GHC:

{- |
A value of type @'IO' [email protected] is a computation which, when performed,
does some I\/O before returning a value of type @[email protected]

There is really only one way to \"perform\" an I\/O action: bind it to
@[email protected] in your program.  When your program is run, the I\/O will
be performed.  It isn't possible to perform I\/O from an arbitrary
function, unless that function is itself in the 'IO' monad and called
at some point, directly or indirectly, from @[email protected]

'IO' is a monad, so 'IO' actions can be combined using either the do-notation
or the '>>' and '>>=' operations from the 'Monad' class.
-}
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))

Это означает, что IO monad объявляется как экземпляр State State# monad, и там определен его >>= (и его реализация довольно легко угадать )забастовкa > .

Подробнее о монаде IO см. IO внутри в статье о Haskell wiki. Также полезно посмотреть Haskell docs, где каждая позиция имеет небольшую ссылку "Источник" справа.

Обновление: И еще одно разочарование, это мой ответ, потому что я не заметил "#" в State#. Однако IO ведет себя как State монада, несущая абстрактный RealWorld состояние

Как @ehird написал State# является компилятором internal и >>= для IO монада определена в GHC.Base module

instance  Monad IO  where
    {-# INLINE return #-}
    {-# INLINE (>>)   #-}
    {-# INLINE (>>=)  #-}
    m >> k    = m >>= \ _ -> k
    return    = returnIO
    (>>=)     = bindIO
    fail s    = failIO s

returnIO :: a -> IO a
returnIO x = IO $ \ s -> (# s, x #)

bindIO :: IO a -> (a -> IO b) -> IO b
bindIO (IO m) k = IO $ \ s -> case m s of (# new_s, a #) -> unIO (k a) new_s

Ответ 3

Они не делают ничего особенного, и просто для последовательности действий. Это поможет, если вы подумаете о них с разными именами:

→ = становится ", а затем, используя результат предыдущего действия,"

→ становится ", а затем"

return становится "ничего не делать, но результат ничего не делает"

Эта функция:

main :: IO ()
main = putStr "hello"
   >>  return " world"
   >>= putStrLn

становится:

main :: IO ()
main = putStr "hello" and then,
       do nothing, but the result of doing nothing is " world"
       and then, using the result of the previous action, putStrLn

В конце концов, нет ничего волшебного в IO. Он точно такой же магический, как точка с запятой в C.