concatMap解释

时间:2016-11-20 22:18:01

标签: haskell

StackOverflow的人们好!

我已经开始使用Haskell了,偶然发现了concatMap函数。 由于我对这种语言很陌生,因此我在理解以下代码时遇到了一些问题(source):

concatMap f = cmap where
    cmap [] = []
    cmap (x : xs) = accum (f x) where
        accum [] = cmap xs
        accum (y : ys) = y : accum ys

据我所知,函数concatMap接受一个函数f

但是我们如何设置一个与另一个相等的功能呢?我们是否将f的结果设为cmap,或者我们是否使用cmap作为f的参数?

非常感谢任何帮助,

提前谢谢!

2 个答案:

答案 0 :(得分:4)

您发布的代码对初学者来说并不容易。幸运的是,我们可以一点一点地重写它:

accum [] = cmap xs
accum (y : ys) = y : accum ys

上面的函数,当输入列表为空时返回cmap xs,否则在y:ys上发出y作为第一个输出元素,然后以递归方式继续输出accum xs

因此,accum zs只会输出zs中的所有元素,然后继续cmap xs。我们可以将其重写为:

accum zs = zs ++ cmap xs

其中++是列表连接。

然后我们可以按如下方式重写整个代码:

concatMap f = cmap where
    cmap [] = []
    cmap (x : xs) = f x ++ cmap xs

我们可以进一步改写为

concatMap f [] = []
concatMap f (x : xs) = f x ++ concatMap f xs

对于初学者来说应该更容易访问。更为非正式地,上述定义满足等式:

concatMap f [x1,x2,...,xn] =
   f x1 ++ f x2 ++ ... ++ f xn ++ []

因此,我们可以看到concatMap的作用。它将f应用于每个列表元素,并且每个列表元素f必须返回一个列表。然后,连接所有这些列表。

例如:

concatMap (\x -> [1..x]) [3,1,2] =
   [1,2,3] ++ [1] ++ [1,2] =
   [1,2,3,1,1,2]

答案 1 :(得分:3)

chi的答案涵盖了concatMap如何运作,因此我将专注于您的一个疑问:

  

但是我们如何设置一个与另一个函数相等的函数呢?

Haskell中的函数是一个值,就像任何其他函数一样。

GHCi> foo = "foo"

这是foo的定义,恰好是一个字符串:

GHCi> :t foo
foo :: [Char]
GHCi> putStrLn foo
foo

以同样的方式......

GHCi> add = (+)

......这是add的定义,恰好是一个函数:

GHCi> :t add
add :: Num a => a -> a -> a
GHCi> add 2 3
5

在上面的定义中,为了强调我只是定义了一个值,我没有明确地写出add的任何一个参数。但这样做完全没问题:

GHCi> add x y = (+) x y

(请注意,x + y,这就是我们通常编写上述定义右侧的方式,只是(+) x y的方便替代语法。)

编写定义的另一种方式是利用部分应用程序来仅提及第一个参数:

GHCi> add x = (+) x

我们也可以,为了它(并且可能澄清正在发生的事情),将(+) x移动到where子句中的单独定义......

GHCi> :{
GHCi| add x = plusX
GHCi|     where
GHCi|     plusX = (+) x
GHCi| :}

...并再次明确地写下第二个参数:

GHCi> :{
GHCi| add x = plusX
GHCi|     where
GHCi|     plusX y = (+) x y
GHCi| :}

plusX是一个函数,它接受一个参数并将其添加到xadd是一个函数,它接受一个参数x,并返回与plusX对应的x函数。这是第二个函数,当我们执行add时,它将第二个参数带到add 2 3(顺便说一下,它等同于(add 2) 3)。

现在,将上述内容与您的concatMap定义进行比较:

concatMap f = cmap where
    cmap [] = []
    cmap (x : xs) = accum (f x) where
        accum [] = cmap xs
        accum (y : ys) = y : accum ys

定义以类似的方式列出。 cmap是一个函数,它使用一个列表并使用fconcatMap的参数)从中生成结果,就像plusX使用x一样1}} add的参数。

所以,总结一下:

  

我们将f的结果设置为等于cmap,还是我们使用cmap作为f的参数?

都不是。我们使用f来定义cmap,然后将其用于定义concatMap整体。