[英]Understanding function definitions and types in Haskell
I am trying to write a simple tool in Haskell as a learning exercise, and have encountered something that I cannot figure out. 我试图在Haskell中编写一个简单的工具作为学习练习,遇到了一些我无法弄清楚的东西。 Here is a simple sample illustrating it.
这是一个简单的例子来说明它。
idMap :: a -> a
idMap x = map id x
main = do
print $ idMap [1, 2]
According to my understanding, this example should compile and print [1, 2]
when run. 根据我的理解,这个例子应该在运行时编译并打印
[1, 2]
。 However, if fails to compile with the following message: 但是,如果无法使用以下消息进行编译:
source_file.hs:2:18: error:
• Couldn't match expected type ‘[b0]’ with actual type ‘a’
‘a’ is a rigid type variable bound by
the type signature for:
idMap :: forall a. a -> a
at source_file.hs:1:10
• In the second argument of ‘map’, namely ‘x’
In the expression: map id x
In an equation for ‘idMap’: idMap x = map id x
• Relevant bindings include
x :: a
(bound at source_file.hs:2:7)
idMap :: a -> a
(bound at source_file.hs:2:1)
It kind of makes sense, given that the signature of map
is (a -> b) -> [a] -> [b]
so the input type is not necessarily the same as the output type, but the signature of id
is a -> a
so surely it follows that map id
would have a signature of (a -> a) -> [a] -> [a]
? 考虑到
map
的签名是(a -> b) -> [a] -> [b]
所以输入类型不一定与输出类型相同,但id
的签名是a -> a
id
a -> a
肯定地说map id
会有(a -> a) -> [a] -> [a]
的签名吗?
The second part I don't really understand is why this is an exception given that all the types ( a
and b
as above) are Integer
. 我不太明白的第二部分是为什么这是一个例外,因为所有类型(如上所述的
a
和b
)都是Integer
。 It would make sense to me that since the signature of idMap
is a -> a
, there should only be a compile exception if it is used in a situation where the output type is expected to be different from input type. 对我来说有意义的是,由于
idMap
的签名是a -> a
,如果在输出类型与输入类型不同的情况下使用它,则应该只有编译异常。
Finally, how would I make this code actually work? 最后,我将如何使这段代码真正起作用? My real code is a little more complicated and I am relying on the output type matching the input type elsewhere in the code so I don't want to change the signature of
idMap
, I want to know what I would need to do to write a function with that signature. 我真正的代码有点复杂,我依赖于输出类型匹配代码中其他地方的输入类型,所以我不想更改
idMap
的签名,我想知道我需要做什么来写一个具有该签名的功能。
You are applying idMap
to a list. 您正在将
idMap
应用于列表。 Therefore, we know the argument type should be some list type. 因此,我们知道参数类型应该是一些列表类型。 Further, you expect the return type to be a list (
[1,2]
), so the return type should be a list as well. 此外,您希望返回类型是一个列表(
[1,2]
),因此返回类型也应该是一个列表。 Since the id
function is fully polymorphic ( a -> a
), we can map
it over a list of any type a
and return a list of items of the same type a
. 由于
id
函数是完全多态的( a -> a
),我们可以map
它map
到任何类型a
的列表,并返回相同类型a
的项列表。 Thus, your final type signature should be [a] -> [a]
. 因此,您的最终类型签名应为
[a] -> [a]
。
Regarding your second question, while it's true that the argument type and return type are both the same, the type as a -> a
is not true for all types a
. 关于你的第二个问题,虽然参数类型和返回类型都是相同的,但对于所有类型
a
,类型为a -> a
不是真的。 Based on the type signature of map
, idMap
must accept a list argument. 根据
map
的类型签名, idMap
必须接受list参数。 We can declare type signatures for functions that are more constrained than necessary, but not less. 我们可以为比必要的约束更多的函数声明类型签名,但不能更少。
Your implementation of idMap
... 你的
idMap
实现......
idMap x = map id x
... involves applying map id
on x
. ...涉及在
x
上应用map id
。 As a consequence, x
must be a list. 因此,
x
必须是一个列表。
GHCi> :t map id
map id :: [b] -> [b]
This will work just fine: 这将工作得很好:
idMap :: [a] -> [a]
idMap x = map id x
Note that, thanks to the use of id
, x
and idMap x
do have the same type (as do their elements), as you expected. 请注意,由于使用了
id
, x
和idMap x
确实具有相同的类型(就像它们的元素一样),正如您所期望的那样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.