为什么我可以在没有显式或隐式定义的情况下使用 `>>=`?
Why can I use `>>=` without an explicit or implicit definition?
我定义了一个类型 X
为
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
您可能会说,到目前为止,我一直无法为 >>=
提出一个定义,因此将其排除在外。我预计这会在编译时出错,但实际上,它所做的只是发出警告。好吧,所以它不会检查 class 的所有方法是否都已定义,但我确实不能 use >>=
。不对,又错了。令我非常惊讶的是,GHCi 愉快地计算 let x = pure 5 >>= pure
。 Control.Monad
没有导出 >>=
的默认定义,我当然没有定义,这怎么可能?
根据您更正的定义,如果我尝试定义然后使用 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
但从未尝试评估结果。因为 Haskell 是惰性的,所以 let x = ...
实际上什么都不做。 x
只会在您实际尝试使用它时(例如,runX
)进行评估,所以那是您遇到错误的时候。
另一种可能是您使用了 let
而未指定类型:
λ> let x = pure 5 >>= pure
λ> x
5
在这里,x
在它使用的 monad m
中是多态的。要打印对像这样的多态术语有用的东西,ghci 默认 m
到 IO
,它可以正常工作并给你 5
,但不会告诉你任何关于你的自定义 monad 的有用信息。
我定义了一个类型 X
为
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
您可能会说,到目前为止,我一直无法为 >>=
提出一个定义,因此将其排除在外。我预计这会在编译时出错,但实际上,它所做的只是发出警告。好吧,所以它不会检查 class 的所有方法是否都已定义,但我确实不能 use >>=
。不对,又错了。令我非常惊讶的是,GHCi 愉快地计算 let x = pure 5 >>= pure
。 Control.Monad
没有导出 >>=
的默认定义,我当然没有定义,这怎么可能?
根据您更正的定义,如果我尝试定义然后使用 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
但从未尝试评估结果。因为 Haskell 是惰性的,所以 let x = ...
实际上什么都不做。 x
只会在您实际尝试使用它时(例如,runX
)进行评估,所以那是您遇到错误的时候。
另一种可能是您使用了 let
而未指定类型:
λ> let x = pure 5 >>= pure
λ> x
5
在这里,x
在它使用的 monad m
中是多态的。要打印对像这样的多态术语有用的东西,ghci 默认 m
到 IO
,它可以正常工作并给你 5
,但不会告诉你任何关于你的自定义 monad 的有用信息。