如何在类型类中指定两个操作通勤?

时间:2010-12-23 19:53:10

标签: haskell typeclass commutativity

我开始阅读this paper on CRDTs,这是一种通过确保修改数据的操作是可交换的,同时共享可修改数据的方法。在我看来,这将是Haskell中抽象的一个很好的候选者 - 为CRDT提供一个类型类,指定数据类型和在该类型上通信的操作,然后努力使库实际共享并发进程之间的更新。

我无法想象的是如何表达操作必须在类型类规范中通勤的合同。

举个简单的例子:

class Direction a where
  turnLeft :: a -> a
  turnRight :: a -> a

无法保证turnLeft . turnRightturnRight . turnLeft相同。我认为回退是指定monad定律的等价物 - 使用注释来指定类型系统不强制执行的约束。

4 个答案:

答案 0 :(得分:11)

你想要的是一个包含证明负担的类型类,如下面的伪Haskell:

class Direction a where
    turnLeft  :: a -> a
    turnRight :: a -> a
    proofburden (forall a. turnLeft (turnRight a) === turnRight (turnLeft a))

这里所有实例都必须提供编译器输入检查的函数和证明。这是一厢情愿的想法(对于Haskell而言),因为Haskell没有(好的,有限的)证明概念。

OTOH,Coq是一种可以提取到Haskell的依赖类型语言的证明助手。虽然我之前从未使用Coq's type classes,但快速搜索很有成效,例如:

Class EqDec (A : Type) := {
   eqb : A -> A -> bool ;
   eqb_leibniz : forall x y, eqb x y = true -> x = y }.

所以看起来高级语言可以这样做,但是在降低标准开发人员的学习曲线方面可以做很多工作。

答案 1 :(得分:7)

继TomMD的回答之后,你可以使用Agda来达到同样的效果。虽然它没有类型类,但您可以从记录中获得大部分功能(除了动态调度)。

record Direction (a : Set) : Set₁ where
  field
    turnLeft  : a → a
    turnRight : a → a
    commLaw   : ∀ x → turnLeft (turnRight x) ≡ turnRight (turnLeft x)

我以为我会编辑帖子并回答为什么你不能在Haskell中这样做的问题。

在Haskell(+扩展)中,您可以表示上面的Agda代码中使用的等价。

{-# LANGUAGE GADTs, KindSignatures, TypeOperators #-}

data (:=:) a :: * -> * where
  Refl :: a :=: a  

这代表两种类型相等的定理。例如。 a相当于b a :=: b

我们可以使用构造函数Refl。使用它,我们可以对定理(类型)的证明(值)执行函数。

-- symmetry
sym :: a :=: b -> b :=: a
sym Refl = Refl

-- transitivity
trans :: a :=: b -> b :=: c -> a :=: c
trans Refl Refl = Refl

这些都是类型正确的,因此也是如此。不过这个;

wrong :: a :=: b
wrong = Refl

显然是错误的,确实在类型检查上失败了。

然而,通过这一切,价值和类型之间的障碍并未被打破。价值观,价值水平的功能和证据仍然存在于冒号的一侧;类型,类型级函数和定理存在于另一个。您的turnLeftturnRight是值级函数,因此无法参与定理。

AgdaCoq是依赖类型的语言,其中屏障不存在或允许事物跨越。 Strathclyde Haskell Enhancement (SHE)是Haskell代码的预处理器,它可以欺骗DTP对Haskell的一些影响。它通过复制类型世界中值世界的数据来实现这一点。我不认为它处理重复的价值级功能,如果确实如此,我的预感是这可能太复杂了,无法处理。

答案 2 :(得分:3)

正如已经说过的那样,使用类型系统无法在Haskell中直接强制执行此操作。但是,如果仅仅在注释中指定约束条件并不令人满意,那么作为中间结构,您可以为所需的代数属性提供QuickCheck测试。

checkers package中已经可以找到这些内容。你可能想咨询它以获得灵感。

答案 3 :(得分:2)

  

我无法想象的是如何表达操作必须在类型类规范中通勤的合同。

你无法弄明白的原因是它不可能。你不能在类型中编码这种属性 - 至少不在Haskell中。