Почему импорт Control.Applicative позволяет этому плохому коду проверять тип?
Я помогаю другу изучать Haskell, и он недавно создал такой код, который проверяет тип и создает цикл записи ЦП во время выполнения. Я полностью сбит с толку этим.
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 в этом случае?
Спасибо,
2 ответа
Там нет экземпляра для (->) 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
,
Чтобы понять, что происходит с монадой ридера (как она известна), взгляните на документацию, раздел All About Monads на Reader, и есть некоторые подсказки, разбросанные по всей Typeclassopedia, которые могут помочь.
Control.Applicative
импорт Control.Monad.Instances
и, следовательно, реэкспортирует экземпляры из Control.Monad.Instances
, Это включает Functor
а также Monad
случаи для ((->) r)
,