【问题标题】:Haskell Constraint is no smaller than the instance headHaskell Constraint 不小于实例头
【发布时间】:2011-08-26 15:40:36
【问题描述】:

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

class (Ring.C a) => EuclideanDomain a where
  norm :: a -> Integer

使用此函数,可以以明显的方式对环进行排序:

compare x y = compare (norm x) (norm y)

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

instance (EuclideanDomain a, Eq a) => Ord a where

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

有没有办法做我想做的事?

【问题讨论】:

    标签: haskell


    【解决方案1】:

    hammar 已经提供了解决方案;我想指出这个例子的另一个问题。你要表达的是“只要一个类型是EqEuclideanDomain的实例,就使用这个规则为Ord创建一个实例。”但这在 Haskell 中是无法表达的。线

    instance (EuclideanDomain a, Eq a) => Ord a where
    

    实际上的意思是,“使用此规则为任何类型创建 Ord 实例。如果 EuclideanDomainEq 的实例不在范围内,则会出错”。这不好,因为这条规则会与所有其他 Ord 实例重叠。

    基本上任何时候你想写一个实例Class typevar,你都需要一个新类型。

    【讨论】:

      【解决方案2】:

      为了避免无限循环,编译器通常要求实例的约束比实例本身“小”,这样算法才会终止。您的实例不会使 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)
      

      现在约束小于实例头,因为它们剥离了newtype。无需扩展。

      【讨论】:

      • 约束变小是什么意思? EuclideanDomain as 肯定比as 少吗?
      • @Xodarap:像“包装在更少的类型构造函数中”那样更小,而不是像“这种类型的更少值”那样。
      • 我明白了。当我尝试你放在这里的东西然后f :: EuclideanDomain a => a -> Orderingf x = compare x x 它不会编译。我错过了什么?
      • @Xodarap:如果没有扩展,这条规则非常简单。实例头必须是T a1 .. an 的形式,并且约束可能只适用于as。但是,使用FlexibleContexts,您可以拥有类似instance C1 (Foo a) => C2 (Bar (Foo a)) 的代码,而这里上下文中的Foo a 小于实例头部中的Bar (Foo a)
      • @Xodarap:你必须使用newtype。所以它将是f :: (EuclideanDomain a, Eq a) => ByNorm a -> Ordering,或者在这种情况下只是不受限制的f :: Ord a => a -> Ordering
      猜你喜欢
      • 1970-01-01
      • 2015-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多