我不是作为Eq成员的意思。我的代码:
data Race = Terran | Zerg | Protoss deriving (Eq, Show, Read);
data MU = MU Race Race deriving (Eq, Show);
在这种情况下,我定义了例如(MU Terran Zerg)
。我想创建一个数据构造函数TvZ
,它在intance的各个方面基本相同,所以我可以匹配一个函数模式:
foo TvZ = ...
而不是必须
foo (MU Terran Zerg) = ...
如果您将其分配给tvZ = (MU Terran Zerg)
我想要做的另一件事是制作简短的表单,就像使类型构造函数T
和Terran
相同。
最后一点,medivac的速度提升需要我感觉到的轻微神经。
答案 0 :(得分:8)
您要求的内容称为“模式同义词”,并已多次提出。目前尚未实施。您可以查看提案here,here以及其他一些地方(链接由hammar提供)。
然而,作为一种解决方案,这也同样适用:
foo (MU Terran Zerg) = ...
foo (MU Zerg Terran) = foo $ MU Terran Zerg
并且会有效地实现同样的目标,即使它看起来不那么好。
答案 1 :(得分:6)
首先尝试使用以下模式(我假设允许MU Terran Terran
和其他自我关系。):
foo (MU Terran Terran) = ...
foo (MU Terran Zerg) = ...
foo (MU Terran Protoss) = ...
foo (MU Zerg Zerg) = ...
foo (MU Zerg Protoss) = ...
foo (MU Protoss Protoss) = ...
foo (MU x y) = foo (MU y x)
你必须非常小心这样定义的函数,因为如果你没有让案例详尽无遗,那就是无限循环。
第二次尝试:我试图概括模式,我想出的最好的就是这个,这几乎没有更好:
forceSymmetric :: (MU -> Maybe r) -> MU -> r
forceSymmetric f = \p -> case f p of
Nothing -> fromJust (f (swap p))
Just r -> r
foo (MU Terran Terran) = Just ...
foo (MU Terran Zerg) = Just ...
foo (MU Terran Protoss) = Just ...
foo (MU Zerg Zerg) = Just ...
foo (MU Zerg Protoss) = Just ...
foo (MU Protoss Protoss) = Just ...
foo (MU x y) = Nothing
如果你搞砸了,你就会产生错误,而不是无限循环。
第三,更深入的尝试:问题的核心是你想要对称。让我们忘记MU
是一个构造函数,并将它视为一个函数。你希望它遵守这种对称性法则:
MU a b == MU b a
按==
我不一定是Eq
类型,而是相互替代性;将一个表达式替换为另一个表达式不应影响任何程序的含义。
嗯,代数数据类型没有那个属性,句号。对于MU
,MU a b == MU c d
等代数数据类型构造函数,当且仅当a == b
和c == d
时。因此,如果您希望任何函数无法区分MU Terran Zerg
和MU Zerg Terran
,则需要使MU
类型为抽象,以便其用户无法看到其内部表示。< / p>
一次 n 项目的 n 项目的组合公式,允许重复,为factorial (n + r - 1) / (factorial r * factorial (n - 1))
;对于n = 3
和r = 2
,这是6种组合。所以我们想要的是定义一个只有六个可能值的类型MU
,一个toMU :: Race -> Race -> MU
函数mu a b == mu b a
和一个fromMU :: MU -> (Race, Race)
函数{{1} }。我能想到的最简单的方法是使用已排序的元组:
uncurry toMU . fromMU == id
现在您可以保证data Race = Terran | Zerg | Protoss deriving (Eq, Show, Read, Ord);
data SortedPair a = SP a a -- The constructor here needs to be private
makeSortedPair :: Ord a => a -> a -> SortedPair a
makeSortedPair a b | a < b = SP a b
| otherwise = SP b a
breakSortedPair :: SortedPair a a -> (a, a)
breakSortedPair (SP a b) = (a, b)
type MU = SortedPair Race
toMU :: Race -> Race -> MU
toMU = makeSortedPair
fromMU :: MU -> (Race, Race)
fromMU = breakSortedPair
可以产生fromMU
但不能产生(Terran, Zerg)
,因此您可以省略上述前两个提案中的最终“全能”案例。 (然而,编译器对此一无所知,因此它仍会抱怨非详尽的模式。)
答案 2 :(得分:0)
从GHC 7.8开始,您可以使用pattern synonyms,这是一个针对此用例的新语言扩展程序:
{-# LANGUAGE PatternSynonyms #-}
pattern TvZ :: MU
pattern TvZ = MU Terran Zerg
这将允许您在模式上下文(即匹配)和表达式上下文(即构造新的TvZ
值)中使用MU
。