6

我想编写一个 Haskell 函数,它返回一个附加到自身计数时间的列表(就像lst * count在 Python 中一样)。

我的第一次尝试是:

self_append_n :: Int -> [a] -> [a]
self_append_n = concat . replicate

我的推理是replicate接受一个计数和一个值,并产生一个值列表。当值本身是一个列表时,剩下的就是将这些列表连接在一起。但是,这会产生一个令人困惑的错误:

Couldn't match type `[a0]' with `[a] -> [a]'
Expected type: [[a0]] -> [a] -> [a]
  Actual type: [[a0]] -> [a0]
In the first argument of `(.)', namely `concat'
In the expression: concat . replicate
In an equation for `self_append_n':
    self_append_n = concat . replicate

然后我写了一个有意义的版本:

self_append_n a b = concat $ replicate a b

它有效!

为什么免点版本编译失败,加点就可以了?

4

1 回答 1

11

明确地将签名括起来可能会有所帮助:

selfAppend :: Int -> ([a]         -> [a])
replicate  :: Int -> ([a]->[[a]])
concat     ::          [[a]]      -> [a]

如果您尝试撰写concat . replicate,您最终会给出concat部分应用的结果replicate,即[a] -> [[a]]。这与[[a]].

您需要做的是在传递结果之前首先将两个参数replicate传递给。IMO 最好的方法是“半无点”:

selfAppend n = concat . replicate n

可读性较差的替代方案是

selfAppend' = curry $ concat . uncurry replicate
selfAppend'' = (concat.) . replicate

或与臭名昭著的运营商

(.:) :: (c->d) -> (a->b->c) -> a->b->d
(.:) = (.).(.)
 -- `≡ fmap fmap fmap`, also a popular implementation...

你可以简单地写

selfAppend''' = concat .: replicate
于 2014-08-31T20:45:59.603 回答