Bool -> [Int] testFn-6ren">
gpt4 book ai didi

haskell - 来自单可遍历的 "concatMap"如何能够与 "pull out"共同论证?

转载 作者:行者123 更新时间:2023-12-02 01:57:20 26 4
gpt4 key购买 nike

我正在学习 Haskell,并且正在为 Yesod 做一个简单的 DB-seed 程序,但我偶然发现了这种我很难理解的行为:

testFn :: Int -> Bool -> [Int]
testFn a b = if b then replicate 10 a else []

Yesod GHCI session :
$ :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]

不知何故,它能够从每个映射中“拉出”第二个“ bool ”到一个单一的柯里化(Currying)参数中。

标准基础 Prelude GHCI session 甚至拒绝编译这个表达式:
$ :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 使用 mono-traversable拥有自己的图书馆 concatMap :
$ :t concatMap
concatMap
:: (MonoFoldable mono, Monoid m) =>
(Element mono -> m) -> mono -> m

以我目前对 Haskell 的理解水平,我无法弄清楚类型是如何在这里分布的。有人可以向我解释(尽可能多地面向初学者)这个技巧是如何完成的吗? testFn 的哪一部分以上符合 Element mono类型?

最佳答案

我们首先列出一些我们知道的类型。 (为了简单起见,我们假设数字是 Int——这并不真正相关。)

testFn :: Int -> Bool -> [Int]
[1,2,3] :: [Int]
True :: Bool
(concatMap testFn [1,2,3]) TrueconcatMap 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 -> ???)

啊哈!如果我们选择 m,我们有一个匹配项如 Bool -> [Int] , 和 mono[Int] .如果我们这样做,我们确实满足了约束 MonoFoldable mono, Monoid m (见下文),我们还有 Element mono ~ Int ,所以一切类型检查。

我们推断 ???[Int]来自 m 的定义.

关于约束:对于 MonoFoldable [Int] ,没什么好说的。 [Int]显然是一个类似列表的类型,带有 Int元素类型,这足以使它成为 MonaFoldableInt作为它的 Element .

对于 Monoid (Bool -> [Int]) , 它有点复杂。我们有任何函数类型 A -> B是一个幺半群,如果 B是一个幺半群。随后以逐点方式执行操作。在我们的具体情况下,我们依赖 [Int]作为一个幺半群,我们得到:
mempty :: Bool -> [Int]
mempty = \_ -> []

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

关于haskell - 来自单可遍历的 "concatMap"如何能够与 "pull out"共同论证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59813038/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com