Pointfree版本没有编译,但有点的版本呢?

rid*_*ish 6 haskell types combinators pointfree function-composition

我想写一个Haskell函数,它返回一个附加到自身计数次数的列表(比如lst * count在Python中).

我的第一次尝试是:

self_append_n :: Int -> [a] -> [a]
self_append_n = concat . replicate
Run Code Online (Sandbox Code Playgroud)

我的理由是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
Run Code Online (Sandbox Code Playgroud)

然后我写了一个有点版本:

self_append_n a b = concat $ replicate a b
Run Code Online (Sandbox Code Playgroud)

它的工作原理!

为什么无点编译无法编译,但添加点可以使它工作?

lef*_*out 11

它可能有助于明确括起签名:

selfAppend :: Int -> ([a]         -> [a])
replicate  :: Int -> ([a]->[[a]])
concat     ::          [[a]]      -> [a]
Run Code Online (Sandbox Code Playgroud)

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

您需要做的是在处理结果之前首先传递两个参数replicate.IMO最好的方法就是"半无点":

selfAppend n = concat . replicate n
Run Code Online (Sandbox Code Playgroud)

可读性较低的替代方案

selfAppend' = curry $ concat . uncurry replicate
selfAppend'' = (concat.) . replicate
Run Code Online (Sandbox Code Playgroud)

或者臭名昭着的运营商

(.:) :: (c->d) -> (a->b->c) -> a->b->d
(.:) = (.).(.)
 -- `? fmap fmap fmap`, also a popular implementation...
Run Code Online (Sandbox Code Playgroud)

你可以简单地写

selfAppend''' = concat .: replicate
Run Code Online (Sandbox Code Playgroud)

  • 我知道了.组合失败,因为复制的实际返回类型不是列表,而是一个函数(它本身返回一个列表). (4认同)