模式同义词可重载 '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
- 令人恼火的是,这些必须是明确的双向模式;特别是因为 'under
where
' 行与实例重载如此直接可比。
- 对于
empty
模式,我必须引入显式 (==)
测试和支持 Eq
约束——以实现简单的模式匹配。 (我想我可以调用一个 isEmpty
方法。)
- 对于
singleton
模式,我避免了显式 (==)
测试,但需要在 class. 中加倍使用方法
- 我真的不喜欢
ViewPatterns
;我希望 PatSyns 可以提供一些方法来避免它们。
如果您可以在 class 实例中放置模式同义词,那么您的解决方案会更简单:您不需要 [=54= 中的 empty
或 singleton
] 因为它们可以根据 PEmpty
和 PSingleton
来定义。唉,如你所知,这在目前的 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 a
(head
的安全版本)很合理一样。
I really do not like ViewPatterns
; I'd hope PatSyns could provide some way to avoid them.
这又是一个“唉”的时刻。很抱歉您不喜欢 ViewPatterns
,但它们几乎是编写双向模式同义词的唯一方法。
你没有提到的最重要的事情是完全模式匹配的问题。您可能会发现,即使您拥有这些新模式,它们也会发出关于非详尽模式匹配的各种警告。您可能想要定义一个更通用的类似“cons”的模式来销毁您的集合。然后,您可以为 PEmpty
和 PCons
添加一个 COMPLETE
pragma。
在接口 (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
- 令人恼火的是,这些必须是明确的双向模式;特别是因为 'under
where
' 行与实例重载如此直接可比。 - 对于
empty
模式,我必须引入显式(==)
测试和支持Eq
约束——以实现简单的模式匹配。 (我想我可以调用一个isEmpty
方法。) - 对于
singleton
模式,我避免了显式(==)
测试,但需要在 class. 中加倍使用方法
- 我真的不喜欢
ViewPatterns
;我希望 PatSyns 可以提供一些方法来避免它们。
如果您可以在 class 实例中放置模式同义词,那么您的解决方案会更简单:您不需要 [=54= 中的 empty
或 singleton
] 因为它们可以根据 PEmpty
和 PSingleton
来定义。唉,如你所知,这在目前的 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 supportingEq
constraint -- to achieve a simple pattern match. (I suppose I could call anisEmpty
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 a
(head
的安全版本)很合理一样。
I really do not like
ViewPatterns
; I'd hope PatSyns could provide some way to avoid them.
这又是一个“唉”的时刻。很抱歉您不喜欢 ViewPatterns
,但它们几乎是编写双向模式同义词的唯一方法。
你没有提到的最重要的事情是完全模式匹配的问题。您可能会发现,即使您拥有这些新模式,它们也会发出关于非详尽模式匹配的各种警告。您可能想要定义一个更通用的类似“cons”的模式来销毁您的集合。然后,您可以为 PEmpty
和 PCons
添加一个 COMPLETE
pragma。