Bry*_*and 5 haskell functional-programming function-composition
所以这个问题很简单,但我似乎无法理解这个概念。
要组成普通函数,可以执行以下操作:
lowerNoSpaces = filter (/= ' ') . map toLower
Run Code Online (Sandbox Code Playgroud)
但是,有时候,这有时行不通:
myConcatMap = concat . map
Run Code Online (Sandbox Code Playgroud)
它给出了错误:
<interactive>:236:1: error:
* Non type-variable argument
in the constraint: Foldable ((->) [a1])
(Use FlexibleContexts to permit this)
* When checking the inferred type
concattMap :: forall a1 a2.
Foldable ((->) [a1]) =>
(a1 -> a2) -> [a2]
Run Code Online (Sandbox Code Playgroud)
但是当相同的函数表示为:
myConcatMap = (concat .) . map
Run Code Online (Sandbox Code Playgroud)
它完全按预期工作。
我知道这是有原因的,但是我一直盯着它看了一阵子,但仍然不太明白为什么原版不起作用而本原版却起作用。
为什么会有两个“。” 的?
che*_*ner 12
从(.)Haskell语法的定义和知识中很容易得出这一点。
您从的更明确定义开始myConcatMap,即
\f -> \xs -> concat (map f xs)
Run Code Online (Sandbox Code Playgroud)
根据组合运算符的定义,您可以将其写为
\f -> concat . (map f)
Run Code Online (Sandbox Code Playgroud)
使用.前缀位置而不是中缀运算符来重写它。
\f -> (.) concat (map f)
Run Code Online (Sandbox Code Playgroud)
并添加一些多余的括号,因为函数应用是左关联的。
\f -> ((.) concat) (map f)
Run Code Online (Sandbox Code Playgroud)
使用部分语法重写此代码以.再次使中缀运算符
\f -> (concat .) (map f)
Run Code Online (Sandbox Code Playgroud)
并应用的定义,(.)一个更多的时间,使用功能(concat .)和map:
(concat .) . map
Run Code Online (Sandbox Code Playgroud)
这是因为map是两个参数的函数,并且您只想concat在提供两个参数后才应用。请记住,Haskell多参数函数是经过咖喱处理的,即实际上
map :: (a->b) -> ([a]->[b])
Run Code Online (Sandbox Code Playgroud)
因此,如果您编写构图c . map,则的参数c必须为type [a]->[b]。但是,的参数concat应该是一个列表,即type [b]或实际上[[e]]。
解决方案:
显式传递第一个参数。
myConcatMap f = concat . map f
Run Code Online (Sandbox Code Playgroud)
之所以map f可行[a] -> [b],是因为它不再是单参数函数,因此您可以concat在其前面进行编写。
concat在函数前面编写,这是应用map到其第一个参数的结果。这就是您在示例中所做的。