模式同义词可重载 'smart constructors'

Pattern synonyms as overloadable 'smart constructors'

在接口 (class) 中包含 'smart constructor' 方法是一个优良传统:

class Collection c a  where 
  empty :: c a
  singleton :: a -> c a
  -- etc

最好将它们作为模式同义词提供:

{-# LANGUAGE  PatternSynonyms  #-}
instance Ord a => Collection [] a  where
  empty = []
  singleton x = [x]
  pattern PEmpty = []
  pattern PSingleton x = [x]

但是你不能把 PatSyns 放在 classes 里面。我有一些工作,但它似乎有很多难看的代码。任何人都可以建议清理它的方法吗? (下面列出了具体的丑陋之处。)

{-# LANGUAGE  ViewPatterns  #-}
pattern PEmpty :: (Eq (c a), Collection c a) => c a
pattern PEmpty <- ((==) empty -> True)  where   
  PEmpty = empty                    

pattern PSingleton :: (Ord a, Collection c a) => a -> c a
pattern PSingleton x <- (isSingleton -> Just x)  where    
  PSingleton x = singleton x     

-- needs an extra method in the class:
  isSingleton :: c a -> Maybe a
-- instance ...
  isSingleton [x] = Just x
  isSingleton  _  = Nothing

如果您可以在 class 实例中放置模式同义词,那么您的解决方案会更简单:您不需要 [=54= 中的 emptysingleton ] 因为它们可以根据 PEmptyPSingleton 来定义。唉,如你所知,这在目前的 GHC 中是不可能的。

照原样,您只能在 class 中定义函数和类型,并且无法访问构造函数(如列表示例中的 []:),您需要两个定义模式同义词的函数:一个用于从类型中提取数据,一个用于嵌入其中。

至于你关于丑陋的具体观点,有些是不可避免的,但对于其他人,可能有一个稍微干净的方法。

It's annoying that these need to be explicitly bi-directional patterns; especially since the 'under where' line is so directly comparable to the instance overload.

唉,这个是免不了的。如果无法访问 class 中的构造函数,您需要使用明确的双向模式。

For the empty pattern I have to introduce an explicit (==) test and supporting Eq constraint -- to achieve a simple pattern match. (I suppose I could call an isEmpty method.)

我个人认为使用 isEmpty 方法您的代码会更清晰。对于它的价值,您可以根据需要使用默认签名,例如:

class Collection c a where
  ...
  isEmpty :: c a -> Bool
  default isEmpty :: Eq (c a) => c a -> Bool
  isEmpty = (==) empty

For the singleton pattern, I've avoided an explicit (==) test, but needed to double-up on a method in the class.

你这么说就像你有选择一样,但我不认为你可以只用一个相等性测试来写这个模式。您正在尝试从未知集合中提取一个值,但我看不出如果没有 class 的支持您如何做到这一点。 extractSingleton 方法似乎很合理,就像 headMay :: [a] -> Maybe ahead 的安全版本)很合理一样。

I really do not like ViewPatterns; I'd hope PatSyns could provide some way to avoid them.

这又是一个“唉”的时刻。很抱歉您不喜欢 ViewPatterns,但它们几乎是编写双向模式同义词的唯一方法。


你没有提到的最重要的事情是完全模式匹配的问题。您可能会发现,即使您拥有这些新模式,它们也会发出关于非详尽模式匹配的各种警告。您可能想要定义一个更通用的类似“cons”的模式来销毁您的集合。然后,您可以为 PEmptyPCons 添加一个 COMPLETE pragma。