与 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
在这里作为函数而不是构造函数。但是,我如何才能惯用地为一般 Alternative
s 完成此操作?
编辑 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
子类。我认为这在任何地方都不存在,而且在召唤这样的东西时,功率重量比似乎并不令人鼓舞。
我知道可以像这样对(命名的)构造函数进行模式匹配:
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
在这里作为函数而不是构造函数。但是,我如何才能惯用地为一般 Alternative
s 完成此操作?
编辑 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
子类。我认为这在任何地方都不存在,而且在召唤这样的东西时,功率重量比似乎并不令人鼓舞。