在typeclass实例中错误绑定类型变量 [英] Error binding type variables in instance of typeclass

查看:122
本文介绍了在typeclass实例中错误绑定类型变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个"Shape"类,应该在所有实例上定义"area".区域返回"Area b"(一种数据类型),其中包含一个数字(b属于Num类型类),表示该Shape的区域.

I have a class "Shape" which should have "area" defined on all instances. area returns "Area b" (a data type) that contains a number (b belongs to Num typeclass) signifying the area of that Shape.

Haskell在将b绑定到(x * y)时遇到问题,其中x和y的类型为"a",而"a"的类型也为Num. 我该如何解决? [如果我将(x * y)替换为0,则可以使用,但即使使用(0 :: Int)也不能使用]

Haskell has problem binding that b to (x*y) where x and y are of type 'a' and 'a' is also of typeclass Num. How do I solve this ?? [If i replace (x*y) by 0, it works but doesn't work even with (0::Int)]

代码:

data Unit = Unit | Meter | CentiMeter               deriving Show

data Area a = Area a Unit                           deriving Show

class Shape a where
      area :: (Num b) => a -> Area b

data Rectangle side = Rectangle side side Unit  deriving Show

instance (Num a) => Shape (Rectangle a) where
     area (Rectangle x y unit) = Area (x*y) unit

错误:

[1 of 1] Compiling Main             ( y.hs, interpreted )

y.hs:11:46:
    Could not deduce (a ~ b)
    from the context (Num a)
      bound by the instance declaration at y.hs:10:10-39
    or from (Num b)
      bound by the type signature for
                 area :: Num b => Rectangle a -> Area b
      at y.hs:11:10-52
      `a' is a rigid type variable bound by
          the instance declaration at y.hs:10:15
      `b' is a rigid type variable bound by
          the type signature for area :: Num b => Rectangle a -> Area b
          at y.hs:11:10
    In the second argument of `(*)', namely `y'
    In the first argument of `Area', namely `(x * y)'
    In the expression: Area (x * y) unit
Failed, modules loaded: none.

推荐答案

这里的问题是area的类型签名:

The problem here is area's type signature:

area :: (Num b) => a -> Area b

它说的是给我一个a,我会给你一个Area b,代表你想要的任何 b;你可以选择".因此,例如,我可以给area一个Integer并期望返回一个Area Double.显然,这不是您想要的!

What it says is "give me an a, and I'll give you an Area b for any b you want; you can pick". So, for instance, I could give area an Integer and expect back an Area Double. Clearly, this isn't what you want!

在这种情况下,由于使用x*y类型为 a x*y,因此当出现 b 时会出现错误-您必须提供一个适用于任何数字类型 b ,但是您给出的值仅适用于一个( a ).

In this case, the error arises because you use x*y, which has type a, when b is expected — you have to give a value that works for any numeric type b, but you're giving a value that only works for one (a).

如果将area的类型更改为a -> Area Integer,则可以使用.但是,我有一种感觉,您希望 instance 能够指定区域的类型.为此,您需要使用一种名为 类型家族 <的语言扩展名/a>:

If you changed area's type to a -> Area Integer, or such, then it would work. However, I have a feeling you want the instance to be able to specify what the type of the area is. For this, you'll need to use a language extension called type families:

{-# LANGUAGE TypeFamilies #-}

class (Num (AreaComponent a)) => Shape a where
    type AreaComponent a
    area :: a -> Area (AreaComponent a)

instance (Num a) => Shape (Rectangle a) where
    type AreaComponent (Rectangle a) = a
    area (Rectangle x y unit) = Area (x*y) unit

这表示,对于作为Shape实例的每个类型 a ,都有一个关联类型 AreaComponent a,代表其区域中每个组件的类型.根据Shape的定义,该类型必须是Num的实例.

This says that for every type a that's an instance of Shape, there is an associated type AreaComponent a, representing the type of each component of its area. That type is required to be an instance of Num by the definition of Shape.

如果所有形状都带有数字类型参数,您可以做的另一件事是使实例针对每种形状的类型构造函数,而不是针对完整形状类型本身:

Another thing you could do, if all your shapes take a numeric type parameter, is to make the instances be for the type constructors of each shape, rather than the full shape types themselves:

class Shape sh where
    area :: (Num a) => sh a -> Area a

instance Shape Rectangle where
    area (Rectangle x y unit) = Area (x*y) unit

这篇关于在typeclass实例中错误绑定类型变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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