无法与实际类型匹配预期类型。类型变量不明确 [英] Couldn't match expected type with actual type. The type variables are ambiguous

查看:134
本文介绍了无法与实际类型匹配预期类型。类型变量不明确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试创建一个 Vector 类型类,它对元组起作用我遇到了一些问题

  { - #LANGUAGE TypeFamilies,FlexibleInstances# - } 

class Vector v其中
类型标量v :: *
vplus :: v - > v - > v
vmult :: v - >标量v - > v
vdot :: v - > v - >标量v

实例Num a =>向量(a,a)其中
类型标量(a,a)= a
(a,b)`vplus`(c,d)=(a + c,b + d)$ b $ (a,b)`vmult` m =(a * m,b * m)
(a,b)`vdot`(c,d)= a * c + b * d

问题是我需要显式类型声明来避免混淆。这当然是一个小麻烦,除了 vdot 似乎并不想工作。

  res :: Int 
res =(2,3)`vdot`(5,5)
- 错误:无法匹配预期类型'Int'类型'标量(t0,t1)'
- 类型变量't0','t1'不明确

如果我这样做,这个错误会消失:

  res :: Int 
res = ((2,3)::(Int,Int))`vdot`(5,5)

但是现在我们已经达到了冗长代码的境界,所以它已经不再实用了。 Haskell应该是美丽而简洁的;不显式类型地狱



我会假设GHC能够解析类型标量(a,a)= a 它本身,但即使我完全删除实例声明,错误仍然存​​在。它甚至抱怨当 Vector(Int,Int)是唯一可用的实例。

所以这里发生了什么?



$ b

  res :: Int 
res =(2,3)`vdot`(5,5)

没有什么力量 2 3 Int ,甚至可以是彼此相同的类型。因此, Vector(a,a)实例可能不适用。对于所有的GHC知道你可以打算写另一个实例 Vector(Float,Double) with 类型Scalar(Float,Double)= Int 和一个完全不同的 vdot 实现,并且 res 仍然会输入check。因此, 2 3 的类型不明确,正如GHC告诉你的那样。

这听起来像是你真的想说的:一对(a,b)只能 是<$当 b 是与 a 相同的类型(然后使用c $ c> c $ c> Vector 你写的实例)。您可以在GHC中表示如下:

  instance(a〜b,Num a)=>向量(a,b)其中
类型标量(a,b)= a
(a,b)`vplus`(c,d)=(a + c,b + d)$ b $ (a,b)`vmult` m =(a * m,b * m)
(a,b)`vdot`(c,d)= a * c + b * d

a〜b 是一个等式约束,它声明两种类型 a b 是一样的。现在你的例如 res 可以正常工作:

  * Main> (2,3)`vdot`(5,5):: Int 
25

这是推理,这意味着类型不再含糊不清。




  • vdot 有类型 Vector v => v - > v - >标量v 。因此,对于 res 类型检查,我们需要找到 v ,使得(2, 3):: v (5,5):: v 标量v〜Int

  • 但是(2,3)有一个<$ c形式的类型$ c>(a,b),并且有一个头部形式为 Vector(a,b)的实例。所以,我们必须使用那个实例。 (在原来的程序中,我们无法完成这一步,因为没有足够的一般实例)。

  • 该实例的关联类型定义告诉我们标量(a,b)〜a 。但我们知道标量(a,b)应该是 Int ,所以我们必须有 a〜Int


  • 该实例的约束告诉我们 a〜b ,并且应该有一个实例 Num a 。所以,我们也必须有 b〜Int (实际上 Num Int 成立)。


  • 因此,我们得出结论: 2 :: Int 3 :: Int ,并且自(5,5):: v 也是,我们有 5 :: Int 5 :: Int

  • 现在我们已经确定了在我们的每个重载名称中使用哪种类型的类表达式( 2 3 5 5 vdot ),所以不存在歧义,我们可以最终评估表达式。



Trying to create a Vector typeclass that works on tuples I've run into some problems

{-# LANGUAGE TypeFamilies, FlexibleInstances #-}

class Vector v where
  type Scalar v :: *
  vplus :: v -> v -> v
  vmult :: v -> Scalar v -> v
  vdot  :: v -> v -> Scalar v

instance Num a => Vector (a, a) where
  type Scalar (a,a) = a
  (a, b) `vplus` (c, d) = (a + c, b + d)
  (a, b) `vmult` m = (a * m, b * m)
  (a, b) `vdot`  (c, d) = a * c + b * d

The problem is that I need explicit type declarations for GHC to not get confused. This is of course a minor inconvenience, except vdot doesn't seem to want to work at all.

res :: Int
res = (2, 3) `vdot` (5, 5)
-- error: Couldn't match expected type 'Int' with actual type 'Scalar (t0, t1)'
--        The type variables 't0', 't1' are ambiguous

This error does go away if I do this:

res :: Int
res = ((2, 3) :: (Int, Int)) `vdot` (5, 5)

But now we've reached the realm of verbose code so extreme it just isn't practical anymore. Haskell's supposed to be beautiful and concise; not explicit type hell

I would have assumed GHC was capable of resolving type Scalar (a, a) = a on its own, but the error persists even if I remove the instance declaration completely. It even complains when Vector (Int, Int) is the only instance available.

So what's going on here? And is there a way to get this to work beautifully?

解决方案

In

res :: Int
res = (2, 3) `vdot` (5, 5)

nothing forces 2 and 3 to be Int, or even to be the same type as each other. So, the Vector (a, a) instance might not apply. For all GHC knows you could intend to write another instance Vector (Float, Double) with type Scalar (Float, Double) = Int and a totally different implementation of vdot, and res would still type check. Hence the types of 2 and 3 are ambiguous, as GHC told you.

It sounds like you really want to say: a pair (a, b) can only be an instance of Vector when b is the same type as a (and then use the instance you wrote). You can express that in GHC as follows:

instance (a ~ b, Num a) => Vector (a, b) where
  type Scalar (a,b) = a
  (a, b) `vplus` (c, d) = (a + c, b + d)
  (a, b) `vmult` m = (a * m, b * m)
  (a, b) `vdot`  (c, d) = a * c + b * d

a ~ b is an equality constraint that asserts that the two types a and b are the same.

Now your example res can work correctly:

*Main> (2, 3) `vdot` (5, 5) :: Int
25

Here is the reasoning that means that the types are no longer ambiguous.

  • vdot has type Vector v => v -> v -> Scalar v. So for res to type check, we need to find the v such that (2, 3) :: v, (5, 5) :: v, and Scalar v ~ Int.

  • But (2, 3) has a type of the form (a, b) and there is an instance whose head is of the form Vector (a, b). So, we must use that instance. (In your original program, we cannot make this step because there is no sufficiently general instance.)

  • The associated type definition of that instance tells us that Scalar (a, b) ~ a. But we know Scalar (a, b) was supposed to be Int, so we must have a ~ Int.

  • The constraints of that instance tell us a ~ b and that there should be an instance Num a. So, we must have b ~ Int too (and indeed Num Int holds).

  • So, we concluded that 2 :: Int and 3 :: Int, and since (5, 5) :: v also, we have 5 :: Int and 5 :: Int too.

  • Now we've determined which type class to use for every overloaded name in our expression (2, 3, 5, 5 and vdot), so there is no ambiguity and we can finally evaluate the expression.

这篇关于无法与实际类型匹配预期类型。类型变量不明确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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