组合 concat 和 map 得到 concatMap:为什么是 f?

2024-05-02

这是我对 Haskell 的第一次探索,如果它很明显,请原谅我。

我整个下午都在玩 Haskell,仔细浏览教程HaskellWiki 上的 99 个问题 http://www.haskell.org/haskellwiki/99_questions,使用我自己的列表类型(典型的缺点)。我在继续时添加了“明显”的函数,并且尝试使它们尽可能简洁(尽可能使用无点表示法)

第12个问题是关于对游程编码列表进行解码的问题,即:

> decode [Multiple 5 'a', Single 'b', Multiple 2 'c']
"aaaaabcc"

我考虑过使用map解码每个元素,然后concat结果(感谢谷歌),最后想起我见过类似的东西concatMap在我的阅读中,GHCi 很快证实了这一点:

> :t map
map :: (a -> b) -> [a] -> [b]
> :t concat
concat :: [[a]] -> [a]
> :t concatMap
concatMap :: (a -> [b]) -> [a] -> [b]

看起来重新实现是显而易见的concatMap:

concatMap :: (a -> [b]) -> [a] -> [b]
concatMap = concat . map

除了 GHCi 停止投诉外:

List.hs:110:15:
    Couldn't match expected type `[a] -> [b]'
                with actual type `[a0]'
    Expected type: [[a0]] -> [a] -> [b]
      Actual type: [[a0]] -> [[a0]]
    In the first argument of `(.)', namely `concat'
    In the expression: concat . map

我想不通,就上网查了一下,Prelude中引用的定义其实是:

concatMap f = concat . map f

我不太明白为什么这个 f 是必要的,因为它的类型显然是a -> [b]如签名所指定...

那么为什么是f这里有必要吗?


从标准定义开始,

concat . map f 
 ≡ concat . (map f)
 ≡ \x -> concat ((map f) x)

你的第一个定义给你:

(concat . map) f
 ≡ (\x -> concat (map x)) f
 ≡ concat (map f)

它不会输入检查,因为(map f) :: [a] -> [b], while concat takes [[a]],列表的列表。

请注意,问题中显示的特定错误消息并未描述上述类型检查失败。给定的消息来自声明返回类型concatMap as [a] -> [b],这与[a0],返回类型concat。如果您省略类型签名,则响应为:



    Couldn't match type ‘[a1] -> [b]’ with ‘[[a]]’
    Expected type: (a1 -> b) -> [[a]]
      Actual type: (a1 -> b) -> [a1] -> [b]
    Relevant bindings include
      concatMap :: (a1 -> b) -> [a] (bound at :49:5)
    Probable cause: ‘map’ is applied to too few arguments
    In the second argument of ‘(.)’, namely ‘map’
    In the expression: concat . map
  

这里,在协调返回类型时发生类型错误map参数类型为concat。事实证明,这种情况对于调试更有用,因为它包含类型检查失败原因的提示。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

组合 concat 和 map 得到 concatMap:为什么是 f? 的相关文章

  • 在 Haskell 中将 Maybe Int 转换为 Int

    我正在编写以下代码 并希望找到框字符串中数字的索引 所以我用了findIndex但它返回Maybe Int值 而我只想要Int value 我怎样才能转换Maybe Int to Int值或者有什么方法可以提取Int from Maybe
  • Haskell:Where 与 Let

    我是 Haskell 的新手 我很困惑Where vs Let 它们似乎都提供了相似的目的 我读过一些比较Where vs Let但我很难辨别何时使用它们 有人可以提供一些背景信息或者一些示例来说明何时使用其中一种而不是另一种吗 哪里与让
  • 让 GHC 生成“带进位加法 (ADC)”指令

    下面的代码将表示 192 位数字的两个未装箱字三元组添加到新的未装箱字三元组中 并且还返回任何溢出 LANGUAGE MagicHash LANGUAGE UnboxedTuples import GHC Prim plusWord2 Wo
  • 如何在 Haskell 中获得列表的中间位置?

    我刚刚开始使用 Haskel 学习函数式编程 我正在慢慢度过Erik Meijer 在 Channel 9 的讲座 http channel9 msdn com shows Going Deep Lecture Series Erik Me
  • Haskell,optparse-generic 的未命名命令行参数

    我在用着optparse 通用 https hackage haskell org package optparse generic解析名为的程序的命令行参数example 我有一个带有命名字段的数据类型 记录语法 例如 data Exam
  • 整数转浮点数

    这段代码的工作原理 posToXY Float gt Float gt Integer posToXY a b do let y a b round y 但这不起作用 posToXY Integer gt Integer gt Intege
  • 为什么 Haskell 中有协函子和逆变函子的区别,而范畴论却没有区别?

    这个答案是从范畴论的角度来看的 https math stackexchange com a 661989 72174包括以下语句 事实是 协函子和逆变函子之间没有真正的区别 因为每个函子只是一个协变函子 More in details a
  • 为什么 Haskell 的默认字符串实现是一个字符链接列表?

    Haskell 默认值的事实String众所周知 实现在速度和内存方面都效率不高 据我所知 lists一般来说 在 Haskell 中实现为单链表 并且适用于大多数小型 简单数据类型 例如Int 这似乎不是一个好主意 但是对于String这
  • 无点镜头创建不进行类型检查

    在函数中test 我遍历一个列表 从它的成员生成镜头 然后打印一些数据 当我使用有针对性的呼叫风格时 这会起作用 当我使其成为无点时 它无法进行类型检查 为什么会出现这种情况 我该如何解决这个问题 在我看来 GHC 并没有保留排名较高的信息
  • 持久 selectList 导致错误“无法将类型‘BaseBackend backend0’与‘SqlBackend’匹配”

    我遇到以下编译错误 Couldn t match type BaseBackend backend0 with SqlBackend arising from a use of runSqlite The type variable bac
  • 如何在 Haskell 中向右或向左移动列表的 1 个元素?

    嗨 我一直在寻找答案 但找不到 假设我们有一个像这样的列表 1 10 4 5 3 我怎样才能将 5 向左移动 使这个列表变成 1 10 5 4 3 我尝试过了swapElementsAt通过找到该元素的索引 但它看起来非常不足 swapEl
  • Haskell,堆栈:找到可执行文件

    我正在寻找类似的东西 stack whereis hasktags where whereis行为或多或少类似于 UNIXwhereis命令 hasktags是这样运行的 stack exec hasktags stack exec whe
  • Haskell 中的分类结构

    Hask通常被认为是一个范畴 其对象是类型 态射是函数 然而 我看到 Conor McBride pigworker 警告不要使用Hask多次 1 https stackoverflow com a 45905082 474311 2 ht
  • 如何在 Haskell 中安装库?

    我尝试使用控制 Monad Extra andM https hackage haskell org package extra 1 7 10 docs Control Monad Extra html import Control Mon
  • 使用 FoldLine 解析多个块

    对于这个简化的问题 我试图解析一个如下所示的输入 foo bar baz quux woo hoo xyzzy glulx into foo bar baz quux woo hoo xyzzy glulx 我尝试过的代码如下 import
  • Haskell 中列表列表的笛卡尔积

    给定一个长度列表的列表x所有子列表的长度都相同y 输出y x长度列表x包含每个子列表中的一项 例子 x 3 y 2 1 2 3 4 5 6 Output 2 3 8不同的输出 1 3 5 1 4 5 1 3 6 1 4 6 2 3 5 2
  • 如何在 Haskell 中漂亮地打印表格?

    我想在 Haskell 中漂亮地打印一个类似表格的数据结构 列列表 例如 Table StrCol strings a bc c IntCol ints 1 30 2 DblCol doubles 2 0 4 5 3 2 应该渲染类似 st
  • Haskell 中的尾递归字符串分割

    我正在考虑分割字符串的问题s在一个字符处c 这表示为 break c s 其中 Haskell 库定义break c 足够接近 br br s h t if c h then s else let h t br t in h h t 假设我
  • 你能识别 Haskell 程序中的无限列表吗? [复制]

    这个问题在这里已经有答案了 可能的重复 如何判断列表是否是无限的 https stackoverflow com questions 7371730 how to tell if a list is infinite 在Haskell中 你
  • Haskell - lambda 表达式

    我试图了解什么是有用的以及如何在 Haskell 中实际使用 lambda 表达式 我不太明白使用 lambda 表达式相对于定义函数的约定方式有何优势 例如 我通常会执行以下操作 let add x y x y 我可以简单地打电话 add

随机推荐