Почему импорт 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, но я не знаю. Итак, я думаю, у меня есть два вопроса:

  1. Что такого в импорте Control.Applicative, который позволяет этому случиться?
  2. Что происходит, когда он входит в бесконечный цикл? Что на самом деле пытается выполнить 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),

Другие вопросы по тегам