【问题标题】:Why does `guarded False = fail "skipped"` type-checks?为什么 `guarded False = 未能“跳过”`类型检查?
【发布时间】:2018-06-22 13:53:20
【问题描述】:

我正在关注 Real World Haskell 的书。在关于 Monads 的章节中,他们给出了一个简单的例子,使用列表 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 _ = []

但我想知道是否可以为任何单子重述guarded

由于列表 monad 中的 failfail _ = [],我虽然可以这样做:

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 =&gt; m a,而guarded False 的类型是Monad m =&gt; m a -&gt; m a。那么我对guarded 的第一个定义怎么可能进行类型检查呢?

【问题讨论】:

  • AFAIK, fail 已被弃用,因为它不适合在所有单子中使用。使用来自Control.MonadMonadPlus 类型类中的mzero
  • @AJFarmar 确实 RWH 建议不要使用 fail,因为除非您知道它是如何在您的代码涉及的所有 monad 中实现的,否则它可能会失败。然而,我的问题更多是关于类型检查:请注意 fail "..." 似乎同时使用 Monad m =&gt; m aMonad m =&gt; m a -&gt; m a 进行类型检查。
  • 它使用 (-&gt;) r 的 monad 实例,在本例中为 r ~ m a

标签: haskell monads typechecking


【解决方案1】:

你被有争议的 function monad instance 绊倒了(实际上这在 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`

也就是说,你在 (-&gt;) (m a) monad 上调用 fail,然后是 does not define a custom fail implementation,所以它是 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 的实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-06
    • 1970-01-01
    • 2014-11-10
    • 2021-02-15
    • 1970-01-01
    • 1970-01-01
    • 2020-01-01
    • 2018-12-29
    相关资源
    最近更新 更多