[英]Haskell: Using map in function composition
I am relatively new to Haskell so apologies if my question sounds stupid. 我对Haskell相对较新,如果我的问题听起来很愚蠢,那么道歉。 I have been trying to understand how function composition works and I have come across a problem that I was wondering someone could help me with.
我一直试图理解功能组合是如何工作的,我遇到了一个问题,我想知道有人可以帮助我。 I am using map in a function composition in the following two scenarios:
我在以下两个场景中使用函数组合中的map:
map (*2) . filter even [1,2,3,4]
map (*2) . zipWith max [1,2] [4,5]
Although both the filter and zipWith functions return a list, only the first composition works while the second composition throws the below error: 虽然filter和zipWith函数都返回一个列表,但只有第一个组合有效,而第二个组合会抛出以下错误:
"Couldn't match expected type '[Int] -> [Int]' with actual type '[c0]'
Any suggestions would be greatly appreciated. 任何建议将不胜感激。
Recall the type of (.)
. 回想一下
(.)
的类型。
(.) :: (b -> c) -> (a -> b) -> a -> c
It takes three arguments: two functions and an initial value, and returns the result of the two functions composed. 它有三个参数:两个函数和一个初始值,并返回组成的两个函数的结果。
Now, application of a function to its arguments binds tighter than the (.)
operator. 现在,函数对其参数的应用比
(.)
运算符更紧密。 So your expression: 所以你的表达:
map (*2) . filter even [1,2,3,4]
is parsed as: 被解析为:
(.) (map (*2)) (filter even [1,2,3,4])
now, the first argument, map (*2)
is ok. 现在,第一个参数
map (*2)
。 It has type (b -> c)
, where b
and c
is Num a => [a]
. 它有类型
(b -> c)
,其中b
和c
是Num a => [a]
。 However, the second argument is a single list: 但是,第二个参数是单个列表:
Prelude> :t filter even [1,2,3,4]
filter even [1,2,3,4] :: Integral a => [a]
and so the type checker will complain that you're passing a [a]
as an argument when the (.)
function needs a function. 所以当
(.)
函数需要一个函数时,类型检查器会抱怨你传递[a]
作为参数。
And that's what we see: 这就是我们所看到的:
Couldn't match expected type `a0 -> [b0]' with actual type `[a1]'
In the return type of a call of `filter'
In the second argument of `(.)', namely `filter even [1, 2, 3, 4]'
In the expression: map (* 2) . filter even [1, 2, 3, 4]
So... parenthesization! 所以......括号!
Either use the $
operator to add a parenthesis: 使用
$
运算符添加括号:
map (*2) . filter even $ [1,2,3,4]
or use explicit parens, removing the composition of two functions 或使用明确的parens,删除两个函数的组合
map (*2) (filter even [1,2,3,4])
or even: 甚至:
(map (*2) . filter even) [1,2,3,4]
The result of zipWith max [1,2] [4,5]
is a list, not a function. zipWith max [1,2] [4,5]
是一个列表,而不是一个函数。 The (.) operator requires a function as its right operand. (。)运算符需要一个函数作为其右操作数。 Hence the error on your second line.
因此你的第二行错误。 Probably what you want is
可能你想要的是什么
map (*2) (zipWith max [1,2] [4,5])
Your first example does not compile on WinHugs (Hugs mode); 你的第一个例子不能在WinHugs上编译(拥抱模式); it has the same error.
它有同样的错误。 The following will work
以下将有效
(map (*2) . filter even) [1,2,3,4]
as it composes two functions and applies the resulting function to an argument. 因为它组成了两个函数并将结果函数应用于参数。
The following forms are valid: 以下表格有效:
map (* 2) $ filter even [1, 2, 3, 4]
(map (* 2) . filter even) [1, 2, 3, 4]
map (* 2) $ zipWith max [1, 2] [4, 5]
(\xs -> map (* 2) . zipWith max xs) [1, 2] [4, 5]
but not the following: 但不是以下内容:
map (* 2) . filter even [1, 2, 3, 4]
map (* 2) . zipWith max [1, 2] [4, 5]
(map (* 2) . zipWith max) [1, 2] [4, 5]
Why is that so? 为什么会这样? Well, take for example
好吧,举个例子
map (* 2) . zipWith max [1, 2] [4, 5]
it is the same as 它是一样的
(map (* 2)) . (((zipWith max) [1, 2]) [4, 5])
(map (* 2))
has type [Int] -> [Int]
(assuming defaulting for Int
), (((zipWith max) [1, 2]) [4, 5])
has type [Int]
and (.)
has type (b -> c) -> (a -> b) -> a -> c
or ([Int] -> [Int]) -> ([Int] -> [Int]) -> [Int] -> [Int]
in this non-polymorphic case, so this is ill-typed. (map (* 2))
具有类型[Int] -> [Int]
(假设为Int
默认值), (((zipWith max) [1, 2]) [4, 5])
具有类型[Int]
和(.)
有类型(b -> c) -> (a -> b) -> a -> c
或([Int] -> [Int]) -> ([Int] -> [Int]) -> [Int] -> [Int]
在这种非多态的情况下,所以这是错误的类型。 On the other hand ($)
has type (a -> b) -> a -> b
, or ([Int] -> [Int]) -> [Int] -> [Int]
in this non-polymorphic case, so this: 另一方面
($)
在这种非多态的情况下有类型(a -> b) -> a -> b
,或([Int] -> [Int]) -> [Int] -> [Int]
,所以这:
(map (* 2)) $ (((zipWith max) [1, 2]) [4, 5])
is well-typed. 打字很好。
Due to the low precedence of (.)
, Haskell parses 由于
(.)
优先级较低,Haskell解析
map (*2) . filter even [1,2,3,4]
as 如
map (*2) . (filter even [1,2,3,4])
ie compose map (*2)
(a function) with the result of filter even [1,2,3,4]
(a list), which makes no sense, and is a type error. 即组合
map (*2)
(函数)与filter even [1,2,3,4]
的结果filter even [1,2,3,4]
(列表),这是没有意义的,并且是类型错误。
You can fix this using @Theodore's suggestions, or by using ($)
: 您可以使用@ Theodore的建议或使用
($)
来解决此问题:
map (*2) . filter even $ [1,2,3,4]
If you check the type of map it is: (a -> b) -> [a] -> [b]
如果你检查地图的类型是:
(a -> b) -> [a] -> [b]
So, it takes a function of a into b and then a list of a and returns a list of b. 因此,它需要a的函数进入b然后是a的列表并返回b的列表。 Right?
对?
Now, you already provide a function of a into b by passing the parameter (*2)
. 现在,您已经通过传递参数
(*2)
提供了a到b的函数。 So, your partially applied map function end up being: [Integer] -> [Integer]
meaning that you will receive a list of integers and return a list of integers. 因此,部分应用的map函数最终为:
[Integer] -> [Integer]
意味着您将收到一个整数列表并返回一个整数列表。
Up to this point, you could compose (.) a function that has the same signature. 到目前为止,您可以编写(。)具有相同签名的函数。 If you check what is the type of
filter even
you would see that it is: [Integer] -> [Integer]
, as such a valid candidate for composition here. 如果你检查什么是
filter even
的类型,你filter even
会看到它是: [Integer] -> [Integer]
,这里是一个有效的合成候选者。
This composition then, does not alter the final signature of the function, if you check the type of: map (*2) . filter even
如果检查类型:
map (*2) . filter even
,则此合成不会改变函数的最终签名map (*2) . filter even
map (*2) . filter even
it is [Integer] -> [Integer]
map (*2) . filter even
是[Integer] -> [Integer]
This would not be the case of the map (*2) . zipWith max [1,2] [4,5]
这不是
map (*2) . zipWith max [1,2] [4,5]
的情况map (*2) . zipWith max [1,2] [4,5]
map (*2) . zipWith max [1,2] [4,5]
because the zipWith max
does not have the same signature as the one expected by map (*2)
. map (*2) . zipWith max [1,2] [4,5]
因为zipWith max
与map (*2)
期望的签名不同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.