Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
组定义的Haskell typeclass上的约束_Haskell_Math - Fatal编程技术网

组定义的Haskell typeclass上的约束

组定义的Haskell typeclass上的约束,haskell,math,Haskell,Math,我为a提出了这个类型类定义,但我发现了一个反例类型,它实际上不是一个组 下面是类定义和组的实例ℤ₂: class Group g where iden :: g op :: g -> g -> g inv :: g -> g data Z2T = Z0 | Z1 instance Group Z2T where iden = Z0 Z0 `op` Z0 = Z0 Z0 `op` Z1 = Z1 Z1 `op` Z0 = Z1 Z1 `op`

我为a提出了这个类型类定义,但我发现了一个反例类型,它实际上不是一个组

下面是类定义和组的实例ℤ₂:

class Group g where
  iden :: g
  op :: g -> g -> g
  inv :: g -> g

data Z2T = Z0 | Z1

instance Group Z2T where
  iden = Z0
  Z0 `op` Z0 = Z0
  Z0 `op` Z1 = Z1
  Z1 `op` Z0 = Z1
  Z1 `op` Z1 = Z0
  inv Z0 = Z1
  inv Z1 = Z0
但是,
的这些类型签名是必要的,但不足以使类型真正成为组,下面是我编译的反例:

data NotAGroup = N0 | N1

instance Group NotAGroup where
  iden = N0
  N0 `op` N0 = N0
  N1 `op` N0 = N0
  N0 `op` N1 = N0
  N1 `op` N1 = N0
  inv N0 = N0
  inv N1 = N0

在Haskell的
group
typeclass中,我如何编码一个类型成为一个组的足够规则?

您是对的,可以编写违反组法则的
group
typeclass的实例,因为实际上代码中没有任何东西真正说明它们

这与
Monad
类的情况相同,在该类中,一元法则没有以任何方式编写或执行。您可以编写非法的
Monad
实例,就像您可以编写非法的
Group
实例一样

这实际上是在Haskell中可以得到的最好结果,至少不会太多地增加类型签名的复杂性。事实上,要在类型中表达群法则,您可能需要一种完全依赖类型的语言,而Haskell不是


在这样的情况下,法律通常是用注释来写的,可能被称为重写规则,程序员通常有足够的纪律来尊重它们

你不能强制执行这些法律,但你可以记录它们。例如,
Monoid
类记录了任何
Monoid
实例都应该遵守的四条定律:

-- | The class of monoids (types with an associative binary operation that
-- has an identity).  Instances should satisfy the following laws:
--
--  * @mappend mempty x = x@
--
--  * @mappend x mempty = x@
--
--  * @mappend x (mappend y z) = mappend (mappend x y) z@
--
--  * @mconcat = 'foldr' mappend mempty@
群只是一个具有额外逆运算的幺半群。使您的
类成为
幺半群的子类
;然后,您只需要记录逆运算必须遵守的附加定律

class Monoid g => Group g where
  ginverse :: g -> g
  -- ginv must obey the following laws
  -- x `gappend` (ginverse x) == gempty
  -- (ginverse x) `gappend` x == gempty

-- g-prefixed synonym for mappend
gappend :: Group g => g -> g -> g
gappend = mappend

-- g-prefixed synonym for mempty
gempty :: Group g => g
gempty = mempty

这需要依赖类型(例如在Agda中找到,但在Haskell中不存在)或一些Hasochistic类型级别的黑客。这两种方法都不太方便,因为它们会迫使您提供您定义的每个实例的“群体性”证明。编译器不会为您完成证明义务(尽管在有限的情况下,某些模板Haskell可能会为您生成这样的证明)。您不能。对不起,你可能需要调查一下Coq。它是一种依赖类型的编程语言,也被设计用来断言和证明有关程序的定理。它的总体设计有点类似于“扩展”Haskell,但语法有点不同。以下是我如何开始Coq(我在这里也证明了你的反例确实不是一个群体):。Coq还附带了一个工具,可以从已验证的Coq代码中提取Haskell代码(因此您可以在Coq中验证它,然后生成正确代码的Haskell版本)。通过使用
组g
约束并设置
gappend=mappend
gappend>移动到typeclass之外有什么害处?这样,它不可重写,但其行为类似于
mappend
。我看不到:)