首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >mono-traversable中的"concatMap“如何能够”拉出“常见的参数?

mono-traversable中的"concatMap“如何能够”拉出“常见的参数?
EN

Stack Overflow用户
提问于 2020-01-20 02:19:33
回答 1查看 180关注 0票数 9

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

代码语言:javascript
复制
testFn :: Int -> Bool -> [Int]
testFn a b = if b then replicate 10 a else []

Yesod GHCI会话:

代码语言:javascript
复制
$ :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“到单个curried参数中。

Standard base Prelude GHCI会话甚至拒绝编译这个表达式:

代码语言:javascript
复制
$ :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使用的是拥有自己的concatMapmono-traversable

代码语言:javascript
复制
$ :t concatMap
concatMap
  :: (MonoFoldable mono, Monoid m) =>
     (Element mono -> m) -> mono -> m

在我目前对Haskell的理解水平上,我不知道类型是如何在这里分布的。有人能给我解释一下(尽可能多的面向初学者)这个技巧是怎么做到的吗?上述testFn的哪个部分符合Element mono类型?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-20 03:03:10

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

代码语言:javascript
复制
testFn :: Int -> Bool -> [Int]
[1,2,3] :: [Int]
True :: Bool

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

代码语言:javascript
复制
concatMap :: (Int -> Bool -> [Int]) -> [Int] -> Bool -> ???

其中???是结果类型。请注意,由于关联性规则,->将关联到右侧,因此上面的类型与:

代码语言:javascript
复制
concatMap :: (Int -> (Bool -> [Int])) -> [Int] -> (Bool -> ???)

让我们在上面写一个通用类型。我添加了几个空格来标记相似性。

代码语言:javascript
复制
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,所以所有的类型都会检查。

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

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

对于Monoid (Bool -> [Int])来说,这有点复杂。如果B是么半群,则任何函数类型A -> B都是么半群。这通过以逐点方式执行操作来实现。在我们的特定情况下,我们依赖于[Int]是一个么半群,我们得到:

代码语言:javascript
复制
mempty :: Bool -> [Int]
mempty = \_ -> []

(<>) :: (Bool -> [Int]) -> (Bool -> [Int]) -> (Bool -> [Int])
f <> g = \b -> f b ++ g b
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59813038

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档