Немного озадачен следующим кодом. В не-игрушечной версии проблемы я пытаюсь сделать монадическое вычисление в monad Result, значения которого могут быть построены только из IO. Похоже, что магия за IO делает такие вычисления строгими, но я не могу понять, как именно это происходит.IO monad предотвращает короткое замыкание встроенной картыM?
Код:
data Result a = Result a | Failure deriving (Show)
instance Functor Result where
fmap f (Result a) = Result (f a)
fmap f Failure = Failure
instance Applicative Result where
pure = return
(<*>) = ap
instance Monad Result where
return = Result
Result a >>= f = f a
Failure >>= _ = Failure
compute :: Int -> Result Int
compute 3 = Failure
compute x = traceShow x $ Result x
compute2 :: Monad m => Int -> m (Result Int)
compute2 3 = return Failure
compute2 x = traceShow x $ return $ Result x
compute3 :: Monad m => Int -> m (Result Int)
compute3 = return . compute
main :: IO()
main = do
let results = mapM compute [1..5]
print $ results
results2 <- mapM compute2 [1..5]
print $ sequence results2
results3 <- mapM compute3 [1..5]
print $ sequence results3
let results2' = runIdentity $ mapM compute2 [1..5]
print $ sequence results2'
Выход:
1
2
Failure
1
2
4
5
Failure
1
2
Failure
1
2
Failure
Большое спасибо за ваш ответ, chi. Могу ли я спросить, как вы знаете, что определение IO mapM является строгим и что возвращение является ленивым? – NioBium
@NioBium 'Failure >> = f = Failure' отбрасывает' f': нет необходимости продолжать дальше в монадической цепочке. IO имеет определение нижнего рычага, которое нелегко записать, но - запрет на исключения - 'action >> = f' всегда будет вызывать' f', так как вы ожидаете, что, например, 'action >> print 4' в конечном итоге напечатает 4 независимо от того, что делает« действие »(запрет исключений IO и отказ от прерывания). – chi
Справа. Еще раз спасибо! – NioBium