与 Alternative empty 或 Applicative pure 的模式匹配

Pattern matching with Alternative empty or Applicative pure

我知道可以像这样对(命名的)构造函数进行模式匹配:

f1 :: Maybe a -> Bool
f1 Nothing = False
f1 (Just x) = True -- in reality have something that uses x here

f2 :: [a] -> Int
f2 [] = False
f2 x = True

如何为一般的 Alternative 编写类似于

的函数
f :: (Alternative m) => m a -> Bool
f empty = False
f x = True

如果我尝试这样做,我会收到错误 Parse error in pattern: empty。我想这是有道理的,因为 empty 在这里作为函数而不是构造函数。但是,我如何才能惯用地为一般 Alternatives 完成此操作?

编辑 1: 我的实际目标是为自定义结果类型定义一个 Monad 实例(可能还有一个 MonadPlus 实例)。而不是基本的 Either Error Result 类型,它应该支持 Maybe Error(如果可能的话还支持其他 Alternative,如 [Error])作为错误类型,还有一些 Applicative作为结果类型以支持惰性评估,例如使用分词器的结果类型 (Maybe Error, [Tokens])

我想要类似

的东西
instance (Alterantive mErr, Applicative mRes) => Monad (mErr e, mRes a) where
  return x = (empty, pure x)
  (empty, pure x) >>= f = f x
  (err, x) >>= f = (err, x)

你能做的最好的是:

f :: (Eq (m a), Alternative m) => m a -> Bool
f x | x == empty = False
    | otherwise = True

实际上可以使用 -XPatternSynonyms-XViewPatterns:

{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
import Control.Applicative (empty)

pattern Empty :: (Eq (m a), Alternative m) => m a
pattern Empty <- ((==) empty -> True)

f :: (Eq (m a), Alternative m) => m a -> Bool
f Empty = False
f _ = True

Eq 约束中滑动,如在 中,确实是可以做的最好的事情。无论如何,值得强调的是它是有代价的:我们现在坚持使用 Eq 常量,如果我们只是针对 [] 或 [=13= 进行模式匹配,那将是不必要的].避免此问题的常用方法是使用 null :: Foldable t => t a -> Bool。但是,在这里,该选项也不是很好,因为 Foldable 在很大程度上与 Alternative 无关并且与您的用例无关。特别是,不能保证在一般情况下,只有一个值 null 成立,这意味着它可能适用于不是相关 empty 的值Alternative 实例。

那么,最终完全符合要求的唯一工具很可能是一些具有 isEmpty 方法的 Alternative 子类。我认为这在任何地方都不存在,而且在召唤这样的东西时,功率重量比似乎并不令人鼓舞。