Haskell Constraint不小于实例头

Xod*_*rap 31 haskell

有些戒指可以配备标准功能:

class (Ring.C a) => EuclideanDomain a where
  norm :: a -> Integer
Run Code Online (Sandbox Code Playgroud)

使用此功能,可以以明显的方式订购戒指:

compare x y = compare (norm x) (norm y)
Run Code Online (Sandbox Code Playgroud)

但我不知道如何表明这一点.我试着这样做

instance (EuclideanDomain a, Eq a) => Ord a where
Run Code Online (Sandbox Code Playgroud)

但这给了我一些警告,当我启用相关的编译器标志时,它告诉我"约束不小于实例头" - 如果我启用UndecidableInstances,一切都会变成地狱.

有办法做我想要的吗?

Joh*_*n L 33

哈马尔已经提供了解决方案; 我想指出这个例子的另一个问题.你想表达什么是"每当类型的实例Eq,并EuclideanDomain使用此规则使一个实例Ord." 但这在Haskell中无法形容.这条线

instance (EuclideanDomain a, Eq a) => Ord a where
Run Code Online (Sandbox Code Playgroud)

实际上意味着,"使用此规则Ord为任何类型创建实例.如果实例EuclideanDomainEq不在范围内,则会出错".这并不好,因为此规则将与其他所有Ord实例重叠.

基本上,只要你想编写一个实例Class typevar,你就需要一个新类型.


ham*_*mar 25

为了避免无限循环,编译器通常要求实例的约束比实例本身"小",以便算法终止.你的实例a在约束中不会变小,所以这就是编译器所抱怨的.

UndecidableInstances延期解除了这一限制,由您自行决定是否会终止.因此,在使用此扩展时,可以将编译器发送到无限循环.

对此的常见解决方案是添加newtype:

newtype ByNorm a = ByNorm a

instance (EuclideanDomain a, Eq a) => Ord (ByNorm a) where
    compare (ByNorm x) (ByNorm y) = compare (norm x) (norm y)
Run Code Online (Sandbox Code Playgroud)

现在约束比实例头小,因为它们剥离了newtype.无需延期.

  • @Xodarap:较小,如"包含在较少类型的构造函数中",而不是"较少的此类型值". (5认同)
  • 约束变小意味着什么?肯定有更少的`EuclideanDomain a`s然后有`a`s? (3认同)