繁体   English   中英

定义Haskell类型的构造函数是否相等?

[英]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)

我想要做的另一件事是制作简短形式,如使类型构造函数TTerran相同。

最后一点,medivac速度提升需要一个小的nerf我觉得。

你所要求的是一个“模式同义词”,并已多次提出。 目前尚未实施。 您可以查看建议在这里在这里 ,和一堆其他地方(链接哈马尔提供)。

但是,作为解决方案,这也适用:

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

即使它看起来不那么好,也会有效地实现同样的目的。

首先尝试,使用以下模式(我假设允许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 == bc == d 因此,如果你想让任何函数无法区分MU Terran ZergMU Zerg Terran ,你需要使MU类型抽象,以便其用户无法看到它的内部表示。

一次取r 个n项的组合数的公式,允许重复,是factorial (n + r - 1) / (factorial r * factorial (n - 1)) ; 对于n = 3r = 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM