组合 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? 的相关文章

随机推荐