为什么这个实现无效?

Cam*_*all 5 haskell types compiler-errors typeclass parametric-polymorphism

假设我有以下类型签名:

someFunction :: (Eq a, Eq b) => a -> b
Run Code Online (Sandbox Code Playgroud)

实施:

someFunction x = (2 :: Int)
Run Code Online (Sandbox Code Playgroud)

(不要把它放得太远,这只是一个例子).

我对签名的理解是" 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
Run Code Online (Sandbox Code Playgroud)

我想我不明白的是它要求"forall" b.使用这个函数的任何代码都应该只依赖于b一个实例Eq,对吧?在我看来,实现确实符合签名.我的实施怎么样打破了这个签名的期望?

Wil*_*ess 10

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

forall a b. (Eq a, Eq b) => a -> b
Run Code Online (Sandbox Code Playgroud)

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

决定要返回的类型不是您的函数.这是你的功能用途决定了它.

所以你应该能够写作

    let { i :: Int; i = 1;
          n :: Integer; y :: Double;
          n = foo i;   -- foo :: Int -> Integer
          y = foo i    -- foo :: Int -> Double
        }
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,您的函数的唯一实现是没有实现:

foo _ = x where {x = x}
Run Code Online (Sandbox Code Playgroud)

因为你无法产生任何你所要求的类型的价值.那种类型可以是任何东西,你无法了解它.


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

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

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

> foo () :: Bool
False

> foo True :: Int
-9223372036854775807

> foo (0 :: Int) :: Bool
Interrupted.
Run Code Online (Sandbox Code Playgroud)

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

  • @CameronBall我认为它有助于大量可视化隐式类型参数.例如,当我们编写`id True`时,GHC在内部将其扩展为`id @Bool True`,其中`@Bool`部分在`id :: forall a中选择类型`a`.A-> A`.本质上,多态函数是具有一个或多个"类型"参数的函数,需要使用特殊的`@T`语法传递,或者省略,以便类型推断可以为我们填充它们.作为练习,您可以尝试自己添加所有`@T`并查看底层内容(首先打开`TypeApplications`扩展名). (5认同)