我有一个类型为buckets
的函数Integral a => [a] -> Int -> Int -> [[a]]
,我希望以这种方式在foldl
中使用它:
basketsort lst = foldl (f) lst [1..3]
f lst = reverse . concat . (flip buckets 9) lst
函数f
有效,类型为Integral a => [a] -> Int -> [a]
,但如果我减少lst
参数,则编译失败。
是否可以通过curry来减少多个参数,并在不声明f
的情况下在foldl中使用f
的正文?像这样:
basketsort lst = foldl (reverse . concat . (flip buckets 9)) lst [1..3]
答案 0 :(得分:4)
如果展开点运算符的第二个应用程序:
f lst = reverse . concat . (flip buckets 9) lst
==> f lst = (.) (reverse . concat) ((flip buckets 9) lst)
然后,η减少变得明显:
f = (.) (reverse . concat) . (flip buckets 9)
但是来吧,你真的想这样做吗?对于那些在你离开之后维护你的代码的人来说,这不是一个很好的礼物。
答案 1 :(得分:2)
首先:我建议不要仅使用flip
将函数部分应用于第二个参数;使用中缀部分可以做得更好。 (或者,也许bucket
的论点首先应该反过来?)
所以,你要制作
f lst = reverse . concat . (`buckets`9) lst
pointfree。问题是你需要将两个参数传递给合成链中最右边的元素。一种方法是使用 uncurried 形式(因为那时这两个参数只有一个值):
f = curry $ reverse . concat . uncurry (`buckets`9)
另一种方法是使用专门的组合器。 pointless-fun
package has this:
f = reverse . concat .: (`buckets`9)
一个更标准的,虽然IMO相当丑陋的替代方案是使用函数 - 仿函数:你可以映射一个函数,它对应于后面的组合:
f = fmap (reverse . concat) . (`buckets`9)
最好的替代方法是保持名为
的参数basketsort lst = foldl (\l -> reverse . concat . buckets l 9) lst [1..3]