[英]Define Haskell type constructor equality?
我并不是作为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速度提升需要一个小的nerf我觉得。
首先尝试,使用以下模式(我假设允许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 ab == MU cd
当且仅当a == b
和c == d
。 因此,如果你想让任何函数无法区分MU Terran Zerg
和MU Zerg Terran
,你需要使MU
类型抽象,以便其用户无法看到它的内部表示。
一次取r 个n项的组合数的公式,允许重复,是factorial (n + r - 1) / (factorial r * factorial (n - 1))
; 对于n = 3
和r = 2
,这是6种组合。 所以我们想要的是定义一个只有六个可能值的类型MU
,一个函数toMU :: Race -> Race -> MU
这样mu ab == mu ba
,一个函数fromMU :: MU -> (Race, Race)
这样就uncurry toMU . fromMU == id
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)
而不是(Zerg, Terran)
,所以你可以省略上面提到的前两个提案的最终“全能”案例。 (然而,编译器对此一无所知,因此它仍会抱怨非详尽的模式。)
从GHC 7.8开始,您可以使用模式同义词 ,这是一种针对此用例的新语言扩展,其中包括:
{-# LANGUAGE PatternSynonyms #-}
pattern TvZ :: MU
pattern TvZ = MU Terran Zerg
这将允许您在模式上下文(即匹配)和表达式上下文(即构建新的MU
值)中使用TvZ
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.