Понимание примера на Writer Monad
Я узнаю о писательской монаде по книге "Learn You A Haskell".
это кусок кода:
import Control.Monad.Writer
logNumber :: Int -> Writer [String] Int
logNumber num = writer (num, ["Got number: " ++ show num])
multWithLog :: Writer [String] Int
multWithLog = do
a <- logNumber 3
b <- logNumber 5
return (a * b)
При беге multWithLog
, это результат:
*Main> runWriter multWithLog
(15,["Got number: 3","Got number: 5"])
На этой строчке:
a <- logNumber 3
b <- logNumber 5
Легко видеть, что a = 3
а также b = 5
так как они оба умножаются на return
функция.
Я не понимаю, почему эти ценности 3
а также 5
, не должны a
а также b
быть значения, которые содержат внутри Writer
Монада? В этом случае кортежи?
Например, с этим было с Maybe
Монада, a
а также b
было бы 3
а также 5
:
do
a <- Just 3
b <- Just 5
return (a * b)
В этом случае это имеет смысл для меня, так как a
а также b
получить контент внутри Just
, Но с первоначальным примером, a
а также b
только получить часть стоимости.
3 ответа
Легко видеть, что a = 3 и b = 5, так как они оба умножаются на функцию возврата. Я не понимаю, почему эти значения равны 3 и 5. Разве a и b не должны быть значениями, содержащимися в монаде Writer? В этом случае кортежи?
Нет. Я думаю, что самый простой способ ответить на это - просто реализовать Writer
набери и изучи его Monad
экземпляр класса:
newtype Writer w a = Writer { runWriter :: (a, w) }
instance Functor (Writer w) where
fmap f (Writer (a, w)) = Writer (f a, w)
instance Monoid w => Applicative (Writer w) where
pure a = Writer (a, mempty)
Writer (f, w) <*> Writer (a, w') = Writer (f a, w <> w')
instance Monoid w => Monad (Writer w) where
return = pure
Writer (a, w) >>= f = let (b, w') = runWriter (f a)
in Writer (b, w <> w')
tell :: w -> Writer w ()
tell w = Writer ((), w)
Как вы можете видеть в методе экземпляра для >>=
, функция f
применяется к a
значение, а не весь кортеж. Синтаксис a <- logNumber 3
desugared с помощью >>=
так что значение, которое связано с a
будет первым элементом кортежа, который Writer
оборачивается.
В этом случае это имеет смысл для меня, так как
a
а такжеb
получить контент внутриJust
, Но с первоначальным примером,a
а такжеb
только получить часть стоимости.
В этом описании нет ничего плохого, но мы также можем взглянуть на эту ситуацию по-другому. В...
a <- Just 3
... мы могли бы также сказать, что a
получает только часть Just 3
- Just
обертка не делает это. С этой точки зрения, что происходит с...
a <- writer (3, ["Got number: " ++ show 3])
... в достаточной степени похож: a
только получает 3
значение. [String]
аннотации, так сказать, остаются на заднем плане, получая mappend
соединены друг с другом монадическими связями, очень похоже на (>>=)
комбинаты Maybe
так что Just
с Just
дает Just
а также Nothing
с чем-нибудь дает Nothing
,
Идея "значений, содержащихся в монаде" немного размыта. Это отчасти работает, но не строго.
Действительно, монада как таковая не содержит ничего. Знаете, это не скафандр или буррито...
В случае Writer
Вы можете четко сказать, что это тип, значения которого содержат как log-snippets, так и результаты вычислений. Последнее - это то, что вы можете интерпретировать как "содержание" монады, и то, что вы можете получить с помощью a <-
, Но в целом такого контента вообще не должно быть.
На самом деле, чтобы остаться с вашим Maybe
пример:
do a <- Just 3
Nothing
b <- Just 5
return (a * b)
В этом случае Nothing
"Прерывает" вычисление, поэтому Just 5
никогда не вводить значение 5
в a
,
Имейте в виду, что если action :: M T
для какой-то монады M
, затем
do
...
a <- action
может дать a
значение типа T
, (В вашем примере M
является Writer [String]
а также T
является Int
, так a
может иметь только тип Int
.)
Будет ли это на самом деле, как часто, откуда приходят значения и что это означает, зависит от конкретной монады. Тем не менее, законы монады могут многое рассказать о том, как будут вести себя все вычисления. Но, изучая монады, вероятно, лучше всего забыть обо всем этом, просто взглянуть на множество различных примеров и побаловать себя монадами самостоятельно, в какой-то момент вы получите для них интуицию. Не пытайтесь "понять" монады по аналогиям.