我想写一个Haskell函数,它返回一个附加到自身计数时间的列表(如Python中的lst * count
)。
我的第一次尝试是:
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
它有效!
为什么无点版本无法编译,但添加点可以使它工作?
答案 0 :(得分: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