Haskell:在函数组合中使用map

waj*_*eeh 5 syntax haskell map function-composition

我对Haskell相对较新,如果我的问题听起来很愚蠢,那么道歉.我一直试图理解功能组合是如何工作的,我遇到了一个问题,我想知道有人可以帮助我.我在以下两个场景中使用函数组合中的map:

  • map (*2) . filter even [1,2,3,4]
  • map (*2) . zipWith max [1,2] [4,5]

虽然filter和zipWith函数都返回一个列表,但只有第一个组合有效,而第二个组合会抛出以下错误:

"Couldn't match expected type '[Int] -> [Int]' with actual type '[c0]'
Run Code Online (Sandbox Code Playgroud)

任何建议将不胜感激.

Don*_*art 17

回想一下这种类型(.).

(.) :: (b -> c) -> (a -> b) -> a -> c
Run Code Online (Sandbox Code Playgroud)

它有三个参数:两个函数和一个初始值,并返回组成的两个函数的结果.

现在,函数对其参数的应用比(.)运算符更紧密.所以你的表达:

map (*2) . filter even [1,2,3,4]
Run Code Online (Sandbox Code Playgroud)

被解析为:

(.) (map (*2)) (filter even [1,2,3,4])
Run Code Online (Sandbox Code Playgroud)

现在,第一个参数,没问题map (*2).它有型(b -> c),其中bcNum a => [a].但是,第二个参数是单个列表:

Prelude> :t filter even [1,2,3,4]
filter even [1,2,3,4] :: Integral a => [a]
Run Code Online (Sandbox Code Playgroud)

所以类型检查器会抱怨你在函数需要函数[a]时传递一个参数(.).

这就是我们所看到的:

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]
Run Code Online (Sandbox Code Playgroud)

所以......括号!

使用$运算符添加括号:

map (*2) . filter even $ [1,2,3,4]
Run Code Online (Sandbox Code Playgroud)

或使用明确的parens,删除两个函数的组合

map (*2) (filter even [1,2,3,4])
Run Code Online (Sandbox Code Playgroud)

甚至:

(map (*2) . filter even) [1,2,3,4]
Run Code Online (Sandbox Code Playgroud)


The*_*ell 5

结果zipWith max [1,2] [4,5]是列表,而不是函数.(.)运算符需要一个函数作为其右操作数.因此你的第二行错误.可能你想要的是什么

map (*2) (zipWith max [1,2] [4,5])
Run Code Online (Sandbox Code Playgroud)

你的第一个例子不能在WinHugs上编译(拥抱模式); 它有同样的错误.以下将有效

(map (*2) . filter even) [1,2,3,4]
Run Code Online (Sandbox Code Playgroud)

因为它组成了两个函数并将结果函数应用于参数.


JJJ*_*JJJ 5

以下表格有效:

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]
Run Code Online (Sandbox Code Playgroud)

但不是以下内容:

map (* 2) . filter even [1, 2, 3, 4]
map (* 2) . zipWith max [1, 2] [4, 5]
(map (* 2) . zipWith max) [1, 2] [4, 5]
Run Code Online (Sandbox Code Playgroud)

为什么会这样?好吧,举个例子

map (* 2) . zipWith max [1, 2] [4, 5]
Run Code Online (Sandbox Code Playgroud)

它是一样的

(map (* 2)) . (((zipWith max) [1, 2]) [4, 5])
Run Code Online (Sandbox Code Playgroud)

(map (* 2))有类型[Int] -> [Int](假设是默认的Int),(((zipWith max) [1, 2]) [4, 5])有类型[Int](.)类型(b -> c) -> (a -> b) -> a -> c([Int] -> [Int]) -> ([Int] -> [Int]) -> [Int] -> [Int]在这种非多态的情况下,所以这是错误的类型.另一方面($)有类型(a -> b) -> a -> b,或者([Int] -> [Int]) -> [Int] -> [Int]在这种非多态的情况下,所以这个:

(map (* 2)) $ (((zipWith max) [1, 2]) [4, 5])
Run Code Online (Sandbox Code Playgroud)

打字很好.