mono-traversable中的“ concatMap”如何能够“抽取”常见的论点?


9

当我偶然发现这种行为时,我正在学习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类型?

Answers:


6

我们首先列出一些我们知道的类型。(我们假装数字只是Int为了简单起见-这并不是很重要。)

testFn :: Int -> Bool -> [Int]
[1,2,3] :: [Int]
True :: Bool

(concatMap testFn [1,2,3]) True与相同concatMap testFn [1,2,3] True,因此concatMap必须具有与所有这些参数匹配的类型:

concatMap :: (Int -> Bool -> [Int]) -> [Int] -> Bool -> ???

???结果类型在哪里。请注意,由于有关联规则,因此->会在右侧进行关联,因此上述键入与以下内容相同:

concatMap :: (Int -> (Bool -> [Int])) -> [Int] -> (Bool -> ???)

让我们在那上面写一个通用类型。我要添加一些空格来标记相似之处。

concatMap :: (MonoFoldable mono, Monoid m) =>
             (Element mono -> m              ) -> mono  -> m
concatMap :: (Int          -> (Bool -> [Int])) -> [Int] -> (Bool -> ???)

啊哈!如果选择mas Bool -> [Int]monoas ,则我们有一个匹配项[Int]。如果这样做的话,我们确实满足了约束条件MonoFoldable mono, Monoid m(请参见下文),并且我们也有Element mono ~ Int,所以所有类型的检查。

我们推断,???[Int]从的定义m

关于约束:对于MonoFoldable [Int],没有什么可说的。[Int]显然是具有Int元素类型的类似列表的类型,这足以使其MonaFoldableIntas 一起使用Element

对于Monoid (Bool -> [Int]),它要复杂一些。我们认为,如果函数类型A -> B是monoid,则任何函数类型都是Bmonoid。接下来,以点方式执行操作。在我们的特定情况下,我们依靠[Int]成为一个monoid,我们得到:

mempty :: Bool -> [Int]
mempty = \_ -> []

(<>) :: (Bool -> [Int]) -> (Bool -> [Int]) -> (Bool -> [Int])
f <> g = \b -> f b ++ g b

1
很好的解释!解释和对齐类型的方式正是我想要看到的,谢谢!
dimsuz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.