我该如何写,“如果类型类型a,那么a也是这个定义的b的一个实例。” [英] How do I write, "if typeclass a, then a is also an instance of b by this definition."

查看:82
本文介绍了我该如何写,“如果类型类型a,那么a也是这个定义的b的一个实例。”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类型类 MyClass ,并且有一个函数可以产生 String 。我想用这个暗示一个 Show 的实例,这样我就可以将实现 MyClass 的类型传递给展示。到目前为止,我有,

  class MyClass a where 
someFunc :: a - > a
myShow :: a - >字符串

实例MyClass a =>显示一个地方
show a = myShow a

给出错误约束不小于实例头。我也试过,

  class MyClass a where 
someFunc :: a - > a
myShow :: a - >字符串

实例Show(MyClass a)其中
显示a = myShow a

给出错误, Class MyClass'用作类型`。



我该如何正确在Haskell中表达这种关系?
Thanks。



我应该补充一点,我希望通过 MyClass 的特定实例来追踪它根据其类型发出特定的字符串。例如,

  data Foo = Foo 
data Bar = Bar

instance MyClass Foo其中
myShow a =foo

实例MyClass Bar其中
myShow a =bar
$ b $ main = do
print Foo
print Bar


解决方案

为了后人的身体,但是跳到最后才能找到真正的解决方案)

在声明 instance MyClass a =>显示一个,让我们来看看错误约束不小于实例头部。约束是'=>'左侧的类型约束,在这种情况下 MyClass a 。 实例头就是在你写一个实例的类之后的所有东西,在这个例子中 a (在 Show )。 GHC中的一种类型推断规则要求约束的构造函数和变量少于头部。这是所谓'帕特森条件。这些作为保证类型检查终止。



在这种情况下,约束与头部完全相同,即 a ,所以它没有通过这个测试。您可以通过启用删除Paterson条件检查UndecidableInstances ,最可能的是 { - #LANGUAGE UndecidableInstances# - } 编译指示。



情况下,基本上使用类 MyClass 作为 Show 类的类型类别的同义词。像这样创建类同义词是UndecidableInstances扩展的规范用法之一,因此您可以在此安全地使用它。
$ b 'Undecidable'意味着GHC无法证明类型检查将终止。尽管听起来很危险,但启用UndecidableInstances可能发生的最糟糕的情况是编译器会循环,最终在耗尽堆栈之后终止。如果编译,那么显然类型检查终止,所以没有问题。危险的扩展是IncoherentInstances,这听起来很糟糕。

编辑:通过这种方法实现的另一个问题来自于这种情况:

  instance MyClass a =>显示一个位置

数据MyFoo = MyFoo ...派生(显示)

实例MyClass MyFoo其中

现在有两个显示 MyFoo 的实例,这个实例来自derived子句和MyClass实例。编译器不能决定使用哪一个,所以它会用一条错误消息来解决。如果您正在试图使 MyClass 类型的实例不受控制,它们已经具有 Show 实例,必须使用newtypes来隐藏已经存在的Show实例。即使没有 MyClass 实例的类型仍然会发生冲突,因为定义 instance MyClass =>显示一个,因为该定义实际上为所有可能的 a 提供了一个实现(上下文检查稍后进行;不涉及实例选择) p>

所以这就是错误信息以及UndecidableInstances如何让它消失。不幸的是,在实际代码中使用起来很麻烦,因为Edward Kmett解释道。最初的动力是避免在已经存在 MyClass 约束时指定 Show 约束。鉴于此,我要做的只是从 MyClass 中使用 myShow ,而不是 show 。你根本不需要 Show 约束。


I have a typeclass MyClass, and there is a function in it which produces a String. I want to use this to imply an instance of Show, so that I can pass types implementing MyClass to show. So far I have,

class MyClass a where
    someFunc :: a -> a
    myShow :: a -> String 

instance MyClass a => Show a where
    show a = myShow a

which gives the error Constraint is no smaller than the instance head. I also tried,

class MyClass a where
    someFunc :: a -> a
    myShow :: a -> String

instance Show (MyClass a) where
    show a = myShow a

which gives the error, ClassMyClass' used as a type`.

How can I correctly express this relationship in Haskell? Thanks.

I should add that I wish to follow this up with specific instances of MyClass that emit specific strings based on their type. For example,

data Foo = Foo
data Bar = Bar

instance MyClass Foo where
    myShow a = "foo"

instance MyClass Bar where
    myShow a = "bar"

main = do
    print Foo
    print Bar

解决方案

(Edit: leaving the body for posterity, but jump to the end for the real solution)

In the declaration instance MyClass a => Show a, let's examine the error "Constraint is no smaller than the instance head." The constraint is the type class constraint to the left of '=>', in this case MyClass a. The "instance head" is everything after the class you're writing an instance for, in this case a (to the right of Show). One of the type inference rules in GHC requires that the constraint have fewer constructors and variables than the head. This is part of what are called the 'Paterson Conditions'. These exist as a guarantee that type checking terminates.

In this case, the constraint is exactly the same as the head, i.e. a, so it fails this test. You can remove the Paterson condition checks by enabling UndecidableInstances, most likely with the {-# LANGUAGE UndecidableInstances #-} pragma.

In this case, you're essentially using your class MyClass as a typeclass synonym for the Show class. Creating class synonyms like this is one of the canonical uses for the UndecidableInstances extension, so you can safely use it here.

'Undecidable' means that GHC can't prove typechecking will terminate. Although it sounds dangerous, the worst that can happen from enabling UndecidableInstances is that the compiler will loop, eventually terminating after exhausting the stack. If it compiles, then obviously typechecking terminated, so there are no problems. The dangerous extension is IncoherentInstances, which is as bad as it sounds.

Edit: another problem made possible by this approach arises from this situation:

instance MyClass a => Show a where

data MyFoo = MyFoo ... deriving (Show)

instance MyClass MyFoo where

Now there are two instances of Show for MyFoo, the one from the deriving clause and the one for MyClass instances. The compiler can't decide which to use, so it will bail out with an error message. If you're trying to make MyClass instances of types you don't control that already have Show instances, you'll have to use newtypes to hide the already-existing Show instances. Even types without MyClass instances will still conflict because the definition instance MyClass => Show a because the definition actually provides an implementation for all possible a (the context check comes in later; its not involved with instance selection)

So that's the error message and how UndecidableInstances makes it go away. Unfortunately it's a lot of trouble to use in actual code, for reasons Edward Kmett explains. The original impetus was to avoid specifying a Show constraint when there's already a MyClass constraint. Given that, what I would do is just use myShow from MyClass instead of show. You won't need the Show constraint at all.

这篇关于我该如何写,“如果类型类型a,那么a也是这个定义的b的一个实例。”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆