假设我具有以下类型签名:
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
我想我不了解它必须“永久” b
运行的要求。使用此功能的任何代码都应仅基于b
是Eq
实例的事实,对吗?在我看来,实现确实与签名匹配。那我的实现又违反了此签名的期望?
答案 0 :(得分:10)
不,您的类型签名实际上是
forall a b. (Eq a, Eq b) => a -> b
表示您的函数必须可以由调用站点确定的任何类型a
和b
进行调用,只要两者是Eq
的实例。
决定返回哪种类型的不是您的函数。确定结果的是函数的 use 。
所以你应该能够写
let { i :: Int; i = 1;
n :: Integer; y :: Double;
n = foo i; -- foo :: Int -> Integer
y = foo i -- foo :: Int -> Double
}
并且如您所见,该函数的唯一实现是 no 实现:
foo _ = x where {x = x}
因为您无法产生所需的 any 类型的值。这种类型可以是任何东西,而您对此一无所知。
通过 other 类型类实际上可以允许您在此处定义某物,例如
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
来返回我想要的任何类型,只要它是{ {1}}”。没有。 :)