Haskell Constraint is no smaller than the instance head

后端 未结 2 1297
面向向阳花
面向向阳花 2020-12-05 00:13

Some rings can be equipped with a norm function:

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

With this functio

相关标签:
2条回答
  • 2020-12-05 00:35

    In order to avoid infinite loops, the compiler normally requires that the constraints of an instance are "smaller" than the instance itself, so that the algorithm will terminate. Your instance does not make a any smaller in the constraints, so that's what the compiler is complaining about.

    The UndecidableInstances extension lifts this restriction, leaving it up to you to prove that it will terminate. It's thus possible to send the compiler into an infinite loop when using this extension.

    The common solution to this is to add a 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)
    

    Now the constraints are smaller than the instance head, as they strip off the newtype. No extension required.

    0 讨论(0)
  • 2020-12-05 00:52

    hammar's already provided a solution; I'd like to point out another problem with this example. What you want to express is "Whenever a type is an instance of Eq and EuclideanDomain, use this rule to make an instance for Ord." But this is inexpressible in Haskell. The line

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

    actually means, "Use this rule to make an Ord instance for any type. It's an error if instances of EuclideanDomain and Eq aren't in scope". That's not good, because this rule will overlap with every other Ord instance.

    Basically any time you want to write an instance Class typevar, you're going to need a newtype.

    0 讨论(0)
提交回复
热议问题