Почему я могу использовать `>>=` без явного или неявного определения?

Я определил тип X as

newtype X i o = X { runX :: Int -> i -> IO o }

Я сделал экземпляр Functor, Applicative и Monad С

instance Functor (X i) where
  fmap f a = X $ \ i o -> liftA f $ runX a i o

instance Applicative (X i) where
  pure x  = X $ \ _ _ -> return x
  a <*> b = X $ \ i o -> liftA2 (<*>) (runX a i o) (runX b i o)

instance Monad (X i) where
  return = pure
  a >> b = X $ \ i o -> runX a i o >> runX b i o

как вы, вероятно, могли бы сказать, я был, thusfar, не в состоянии придумать определение для >>= и так исключили его. Я ожидал, что это ошибка при компиляции, но на самом деле все, что он сделал, это поднял предупреждение. Хорошо, поэтому он не проверяет, что все методы класса определены, но тогда, конечно, я не могу на самом деле использовать >>=. Нет, опять ошибся. К моему большому удивлению, GHCi с радостью оценивает let x = pure 5 >>= pure. Control.Monad не экспортирует определение по умолчанию >>=, и я, конечно, не определил один, так как это возможно?

1 ответов


учитывая ваше исправленное определение, если я попытаюсь определить, а затем использовать x, Я получаю ожидаемое исключение во время выполнения:

λ> let x = pure 5 >>= pure :: X Int Int
λ> runX x 5 5
*** Exception: foo.hs:12:10-20: No instance nor default method for class operation GHC.Base.>>=

есть две возможные причины, по которым вы этого не увидите.

во-первых, вы только что запустили let но никогда не пытался оценить результат. Поскольку Хаскелл ленив,let x = ... ничего не делает. x будет оцениваться только тогда, когда вы действительно попытаетесь использовать его (с, ie,runX), так вот, когда вы попали в ошибка.

другая возможность заключается в том, что вы используете let без указания типа:

λ> let x = pure 5 >>= pure
λ> x
5

здесь x полиморфен в монаде m он использует. Чтобы напечатать что-то полезное для полиморфных терминов, таких как этот, ghci defaults m to IO, который работает правильно и дает вам 5, но не говорит вам ничего полезного о вашей пользовательской монаде.