4

我知道有可能对(命名的)构造函数进行模式匹配,如下所示:

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

我怎样才能为 general Alternatives 编写这样的函数,类似于

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

如果我尝试这个,我会得到错误Parse error in pattern: empty。我想这是有道理的,作为empty这里的函数而不是构造函数。但是,我怎样才能以Alternative惯用的方式为 general 做到这一点?

编辑 1: 我的实际目标是为自定义结果类型定义一个Monad实例(也可能是一个MonadPlus实例)。除了基本Either Error Result类型,它应该支持 a Maybe Error(如果可能还有其他Alternatives like [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)
4

3 回答 3

5

你能做的最好的事情是:

f :: (Eq (m a), Alternative m) => m a -> Bool
f x | x == empty = False
    | otherwise = True
于 2020-02-19T15:23:45.383 回答
2

实际上可以使用-XPatternSynonymsand -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
于 2020-02-19T16:10:46.933 回答
1

正如mithrandi 的回答那样,加入Eq约束确实是可以做到的最好的。无论如何,值得强调的是它是有代价的:我们现在被困在一个常量上,如果我们只是模式匹配,比如or ,这将是不必要的。避免此问题的常用方法是使用. 但是,在这里,该选项也不是很好,因为它与您的用例基本无关,而且与您的用例完全不同。特别是,在一般情况下,不能保证只有一个值适用,这意味着它可能适用于不属于相关实例的值。Eq[]Nothingnull :: Foldable t => t a -> BoolFoldableAlternativenullemptyAlternative

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

于 2020-02-20T03:17:37.480 回答