首页 > 解决方案 > 为什么这个实现无效?

问题描述

假设我有以下类型签名:

someFunction :: (Eq a, Eq b) => a -> b

通过实施:

someFunction x = (2 :: Int)

(不要看得太远,这只是一个例子)。

我对签名的理解是“someFunction接受一个作为类型类实例的参数Eq,并返回一个作为类型类实例的值(可以是不同类型)Eq”。Int是 的一个实例Eq,那么为什么 GHC 会对这个实现感到不安呢?

该错误使其足够明显:

Couldn't match expected type ‘b’ with actual type ‘Int’
     ‘b’ is a rigid type variable bound by
       the type signature for:
         someFunction :: forall a b. (Eq a, Eq b) => a -> b

我想我不明白的是它“forall”工作的要求bb任何使用此函数的代码都应该只依赖于 的实例这一事实Eq,对吗?在我看来,实现确实与签名匹配。我的实现是否打破了这个签名的期望?

标签: haskelltypescompiler-errorstypeclassparametric-polymorphism

解决方案


不,你的类型签名,实际上是

forall a b. (Eq a, Eq b) => a -> b

意味着您的函数必须可以使用任何类型调用,a并且b调用站点确定,只要两者都是Eq.

决定返回什么类型的不是你的函数。这是您的功能的使用决定了这一点。

所以你应该可以写

    let { i :: Int; i = 1;
          n :: Integer; y :: Double;
          n = foo i;   -- foo :: Int -> Integer
          y = foo i    -- foo :: Int -> Double
        }

如您所见,您的函数的唯一实现是没有实现:

foo _ = x where {x = x}

因为你无法产生任何需要你的类型的值。这种类型可以是任何东西,你无法知道任何关于它的东西。


顺便说一句,其他类型类实际上可能允许你在这里定义一些东西,比如

foo :: (Enum a, Enum b, Bounded a, Bounded b) => a -> b 
foo a = snd . last $ zip [minBound .. a] (cycle [minBound ..])

我并不是说这是一个明智的定义,只是说它是可能的:

> foo () :: Bool
False

> foo True :: Int
-9223372036854775807

> foo (0 :: Int) :: Bool
Interrupted.

对于来自更常用语言的程序员来说,认为这foo :: (Eq a) => a意味着“我可以定义foo 返回任何我想要的类型,只要它在Eq”中,这可能是一个常见的误解。它没有。:)


推荐阅读