为什么 `guarded False = fail "skipped"` 类型检查?
Why does `guarded False = fail "skipped"` type-checks?
我正在关注真实世界 Haskell 这本书。在关于 Monad 的章节中,他们给出了一个简单的例子,使用列表 monad 来计算所有满足 x * y == n
.
的数字对 (x, y)
他们的解决方案是:
multiplyTo :: Int -> [(Int, Int)]
multiplyTo n = do
x <- [1..n]
y <- [x..n]
guarded (x * y == n) $
return (x, y)
guarded :: Bool -> [a] -> [a]
guarded True xs = xs
guarded False _ = []
但我想知道是否可以为任何 monad 重述 guarded
。
因为列表 monad 中的 fail
是 fail _ = []
,我认为我可以这样做:
guarded :: (Monad m) => Bool -> m a -> m a
guarded True = id
guarded False = fail "skipped"
然而,这实际上在 ghci 中失败了:
*Main> multiplyTo 24
*** Exception: skipped
我有一种无法完全解释的预感。这两个版本工作:
guarded :: (Monad m) => Bool -> m a -> m a
guarded True = id
guarded False = \s -> fail "skipped"
guarded :: (Monad m) => Bool -> m a -> m a
guarded True xs = xs
guarded False _ = fail "skipped"
fail "skipped"
的类型是Monad m => m a
,而guarded False
的类型是Monad m => m a -> m a
。那么我对 guarded
的第一个定义怎么可能进行类型检查?
你被有争议的 function monad 实例 绊倒了(实际上这在 Haskell 社区中并没有那么有争议,但我个人认为我们可能有如果它不存在会更好)和无可争议的破坏 fail
方法。
看类型:
guarded False
= fail "skipped" :: m a -> m a
≡ (fail :: String -> (m a -> m a)) "skipped"
≡ (fail :: String -> F (m a)) "skipped" -- with `type F x = m a -> x`
即,您在 (->) (m a)
monad 上调用 fail
,然后 does not define a custom fail
implementation, so it defaults to the error one
fail :: String -> ((->) r) a
fail s = errorWithoutStackTrace s
请注意,如果您从函数中删除 Monad m
约束,这甚至会如何进行类型检查,因为 fail
不使用那个 monad.
你的函数的正确概括是
guarded :: Alternative f => Bool -> f a -> f a
guarded True = id
guarded False = const empty
如果我错误地忘记了 const
,这 不会 进行类型检查,因为函数不是 Alternative
.
的实例
我正在关注真实世界 Haskell 这本书。在关于 Monad 的章节中,他们给出了一个简单的例子,使用列表 monad 来计算所有满足 x * y == n
.
他们的解决方案是:
multiplyTo :: Int -> [(Int, Int)]
multiplyTo n = do
x <- [1..n]
y <- [x..n]
guarded (x * y == n) $
return (x, y)
guarded :: Bool -> [a] -> [a]
guarded True xs = xs
guarded False _ = []
但我想知道是否可以为任何 monad 重述 guarded
。
因为列表 monad 中的 fail
是 fail _ = []
,我认为我可以这样做:
guarded :: (Monad m) => Bool -> m a -> m a
guarded True = id
guarded False = fail "skipped"
然而,这实际上在 ghci 中失败了:
*Main> multiplyTo 24
*** Exception: skipped
我有一种无法完全解释的预感。这两个版本工作:
guarded :: (Monad m) => Bool -> m a -> m a
guarded True = id
guarded False = \s -> fail "skipped"
guarded :: (Monad m) => Bool -> m a -> m a
guarded True xs = xs
guarded False _ = fail "skipped"
fail "skipped"
的类型是Monad m => m a
,而guarded False
的类型是Monad m => m a -> m a
。那么我对 guarded
的第一个定义怎么可能进行类型检查?
你被有争议的 function monad 实例 绊倒了(实际上这在 Haskell 社区中并没有那么有争议,但我个人认为我们可能有如果它不存在会更好)和无可争议的破坏 fail
方法。
看类型:
guarded False
= fail "skipped" :: m a -> m a
≡ (fail :: String -> (m a -> m a)) "skipped"
≡ (fail :: String -> F (m a)) "skipped" -- with `type F x = m a -> x`
即,您在 (->) (m a)
monad 上调用 fail
,然后 does not define a custom fail
implementation, so it defaults to the error one
fail :: String -> ((->) r) a
fail s = errorWithoutStackTrace s
请注意,如果您从函数中删除 Monad m
约束,这甚至会如何进行类型检查,因为 fail
不使用那个 monad.
你的函数的正确概括是
guarded :: Alternative f => Bool -> f a -> f a
guarded True = id
guarded False = const empty
如果我错误地忘记了 const
,这 不会 进行类型检查,因为函数不是 Alternative
.