简体   繁体   English

Haskell:在函数组合中使用map

[英]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) ,其中bcNum 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 maxmap (*2)期望的签名不同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM