Почему импорт Control.Applicative позволяет этому плохому коду вводить проверку?
Я помогаю другу узнать Haskell, и он недавно создал такой код, который проверяет и создает цикл сжигания CPU во время выполнения. Я полностью озадачен этим.
import Control.Monad
import Control.Applicative
main = forever putStrLn "Hello, infinity"
Это не должно вводить проверку, но делает. Правильная версия будет выглядеть следующим образом:
main = forever $ putStrLn "Hello, infinity"
Что странно и удивительно для меня, так это то, что вы получаете разные результаты и без импорта Control.Applicative. Не импортируя его, он не печатает проверку:
Prelude Control.Monad> forever putStrLn "Hello, infinity"
<interactive>:1:1:
No instance for (Monad ((->) String))
arising from a use of `forever'
Possible fix: add an instance declaration for (Monad ((->) String))
In the expression: forever putStrLn "Hello, infinity"
In an equation for `it': it = forever putStrLn "Hello, infinity"
Я не вижу экземпляр Monad для ((->) String
в источнике для Control.Applicative, поэтому я предполагаю, что что-то странное происходит из-за использования Control.Category или Control.Arrow, но я не знать. Поэтому у меня есть два вопроса:
- Что происходит с импортом Control.Applicative, который позволяет это произойти?
- Что происходит, когда он входит в бесконечный цикл? Что Haskell на самом деле пытается выполнить в этом случае?
Спасибо,
Ответы
Ответ 1
Нет экземпляра для (->) String
, но есть экземпляр для (->) e
... и этот экземпляр очень и очень полезен во многих ситуациях. Во втором вопросе мы должны взглянуть на forever
и экземпляр класса для функций:
instance Monad ((->) e) where
return x = \e -> x
m >>= f = \e -> f (m e) e
forever m = m >> forever m = m >>= \_ -> forever m
Теперь, что делает forever putStrLn
?
forever putStrLn
= putStrLn >>= \_ -> forever putStrLn
= \e -> (\_ -> forever putStrLn) (putStrLn e) e
= \e -> (forever putStrLn) e
= forever putStrLn
... это просто чистый бесконечный цикл, в основном идентичный loop = loop
.
Чтобы получить некоторую интуицию для того, что происходит с монадой читателя (как известно), посмотрите документацию, Все О разделе Monads в разделе Reader, и есть несколько намеков, накрытых на Typeclassopedia, которые могут помочь.
Ответ 2
Control.Applicative
импортирует Control.Monad.Instances
и, следовательно, реэкспортирует экземпляры из Control.Monad.Instances
. Это включает Functor
и Monad
экземпляры для ((->) r)
.