3

我不是 Eq 的成员。我的代码:

data Race = Terran | Zerg | Protoss deriving (Eq, Show, Read);

data MU = MU Race Race deriving (Eq, Show);

在这种情况下,我定义例如(MU Terran Zerg)。我想创建一个数据构造函数TvZ,它在实例的所有方面都基本相同,因此我可以匹配一个函数模式:

foo TvZ = ...

而不是必须做

foo (MU Terran Zerg) = ...

如果将其分配给变量,则无法执行此操作tvZ = (MU Terran Zerg)

我想做的另一件事是制作简短的表格,就像制作类型构造函数T一样Terran

最后一件事,我觉得医疗运输车的速度提升需要小幅削弱。

4

3 回答 3

8

您所要求的被称为“模式同义词”,并且已被多次提出。目前尚未实施。您可以在此处此处和许多其他地方查看提案(链接由 hammar 提供)。

但是,作为一种解决方案,这同样适用:

foo (MU Terran Zerg) = ...
foo (MU Zerg Terran) = foo $ MU Terran Zerg

并且将有效地实现相同的目标,即使它看起来不那么好。

于 2013-04-15T04:04:18.933 回答
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类型类,而是相互替代;用一个表达式代替另一个表达式不应影响任何程序的含义。

好吧,代数数据类型没有那个属性,句号。对于代数数据类型构造函数,例如MUMU a b == MU c d当且仅当a == bc == d。所以如果你想让任何函数都无法区分MU Terran Zergand MU Zerg Terran,你需要将MU类型抽象化,这样它的用户就看不到它的内部表示。

一次取r的n 个项目的组合数的公式,允许重复,是;对于和,这是 6 种组合。所以我们想要的是定义一个只有六个可能值的类型,一个这样的函数,和一个这样的函数。我能想到的最简单的方法是使用排序的元组:factorial (n + r - 1) / (factorial r * factorial (n - 1))n = 3r = 2MUtoMU :: Race -> Race -> MUmu a b == mu b afromMU :: MU -> (Race, Race)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),因此您可以从上面的前两个提案中省略最终的“包罗万象”案例。(然而,编译器对此一无所知,所以它仍然会抱怨非详尽的模式。)

于 2013-04-15T06:02:05.657 回答
0

从 GHC 7.8 开始,您可以使用pattern synonyms,这是一种新的语言扩展,主要针对这个用例:

{-# LANGUAGE PatternSynonyms #-}

pattern TvZ :: MU
pattern TvZ = MU Terran Zerg

这将允许您TvZ在模式上下文(即匹配)和表达式上下文(即新MU值的构造)中使用。

于 2016-01-16T14:39:00.927 回答