当我偶然发现这种行为时,我正在学习Haskell,并且正在为Yesod做一个简单的DB种子程序,这种行为我很难理解:
testFn :: Int -> Bool -> [Int]
testFn a b = if b then replicate 10 a else []
Yesod GHCI会议:
$ :t concatMap testFn [3]
concatMap testFn [3] :: Bool -> [Int]
$ (concatMap testFn [1,2,3]) True
[1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3]
它以某种方式能够将每个映射中的第二个“布尔”“拉出”到一个单独的咖喱参数中。
标准基础Prelude GHCI会话甚至拒绝编译此表达式:
$ :t concatMap testFn [3]
error:
• Couldn't match type 'Bool -> [Int]' with '[b]'
Expected type: Int -> [b]
Actual type: Int -> Bool -> [Int]
• Probable cause: 'testFn' is applied to too few arguments
In the first argument of 'concatMap', namely 'testFn'
In the expression: concatMap testFn [3]
事实证明,Yesod使用具有自己的单遍历库concatMap
:
$ :t concatMap
concatMap
:: (MonoFoldable mono, Monoid m) =>
(Element mono -> m) -> mono -> m
以我目前对Haskell的理解水平,我无法弄清楚这里的类型如何分布。有人可以向我(尽可能多地面向初学者)解释这个技巧是如何完成的吗?testFn
以上哪个部分符合Element mono
类型?