如果我硬编码返回值,为什么Haskell会给我一个类型错误?

spi*_*ire 2 haskell functional-programming

我真的不知道为什么这是一个类型错误:

foo :: (Eq a) => a -> a
foo _ = 2
Run Code Online (Sandbox Code Playgroud)

谁能解释一下?

Mic*_*ski 14

因为类型

foo "bar"
Run Code Online (Sandbox Code Playgroud)

应该是String,根据你的签名,但不是(2不是字符串).在你的代码中,foo是通用的,所以它应该返回一个与参数完全相同的实例.

haskell类型系统的强大功能为我们提供了额外的信息 - 你可以用foo中的参数来检查它与其他东西的相等性,但是我可以想出任何新的类型(让我们称之为Baz)并使用foo它 - 你不可能有任何其他Baz实例,所以返回Baz实例的唯一方法是返回与参数完全相同的实例.

如果你像这样重写了foo:

foo _ = True
Run Code Online (Sandbox Code Playgroud)

它会有一个签名foo :: a -> Bool,这基本上是你试图做的,但事情变得更复杂的数字.

一般来说,您的功能有一个签名

foo :: (Num t1) => t -> t1
Run Code Online (Sandbox Code Playgroud)

这意味着它为任何给定的参数返回一个Num实例.(这是因为2可以在haskell中有许多不同的类型,取决于你需要它可以是Int或Real或其他.)

您应该使用ghci中的类型,例如:

:t foo
Run Code Online (Sandbox Code Playgroud)

会给你foo的感染型签名.

:t 2
Run Code Online (Sandbox Code Playgroud)

给出了(Num t) => t哪个意味着2可以是实现Num的任何类型的实例.


Dar*_*rio 5

您声明的类型签名意味着

对于所有类型a(实例化Eq),foo获取此类型的值并返回此类型的另一个值

你甚至可以这样直接写它:

foo :: forall a . Eq a => a -> a
Run Code Online (Sandbox Code Playgroud)

现在是函数定义

foo _ = 2
Run Code Online (Sandbox Code Playgroud)

说了些不同的话:

无论给出什么类型,都要返回一个数字.

当然这种类型是不相容的.

示例:正如Michał所说,既然foo "Hello"给了a String,它应该返回一个字符串,但实际上确实返回一个数字.