Performance 带折叠的优化

Performance 带折叠的优化,performance,functional-programming,ocaml,fold,Performance,Functional Programming,Ocaml,Fold,我只是好奇是否有(仅一阶多态性)折叠优化 对于地图,存在着毁林现象:mapg(mapfls)=>mapg(g.f)ls,以及rev(mapfls)=>rev_-mapfls(在Ocaml中更快) 但是fold是如此强大,似乎无法进行任何优化。显而易见的是: fold_left f acc (List.map g li) => fold_left (fun acc x -> f acc (g x)) acc li fold_right f li acc => fold_left

我只是好奇是否有(仅一阶多态性)折叠优化

对于地图,存在着毁林现象:
mapg(mapfls)=>mapg(g.f)ls
,以及
rev(mapfls)=>rev_-mapfls
(在Ocaml中更快)

但是fold是如此强大,似乎无法进行任何优化。

显而易见的是:

fold_left f acc (List.map g li) => fold_left (fun acc x -> f acc (g x)) acc li
fold_right f li acc => fold_left f acc li (* if (f,acc) is a monoid *)
你可能会对关于“香蕉、镜头、信封和带刺铁丝网的函数式编程”主题的经典论文感兴趣。然而,请注意,它是技术性的,并且具有难以穿透的符号


编辑:我的第一条规则的第一个版本是错误的,多亏了文森特·雨果的编辑。

你可以在褶皱上使用森林砍伐。事实上,
map/map
fusion就是一个特例

诀窍是用一个特殊的
build
函数替换列表构造:

build :: (forall b. (a -> b -> b) -> b -> b) -> [a]
build g = g (:) []
现在,使用
foldr

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr c n []     = n
foldr c n (x:xs) = c x (foldr c n xs)
我们有以下等价物:

foldr c n (build g) == g c n
(事实上,这仅在某些情况下是正确的,但在一般情况下是正确的。有关详细信息,请参阅)

如果使用
build
编写列表生成函数(包括
map
),使用
foldr
编写用户,则上述等式可以删除大多数中间列表。Haskell的列表理解被翻译成
build
foldr
的组合

这种方法的缺点是它不能处理左折叠。不过处理得很好。它将列表生成器和转换器表示为流(共导数据类型,有点像迭代器)。上面的文章可读性很强,所以我建议大家看一看

gasche提到的“香蕉”论文详细介绍了褶皱的种类及其等效性


最后,还有Bird and Moor's,其中提到了一些转换,如。

如果您有兴趣深入了解理论,我建议您阅读一些关于和的内容。虽然围绕它的范畴理论似乎有点吓人,但这个概念并没有那么难

反同构是使用递归数据结构并产生某种值的函数。同构是指给定某个值(一种种子)的函数生成递归数据结构。特别是,在其他Anwer中提到的
foldr
build
是在列表上构建反同构和反同构的函数。但这个概念基本上可以应用于任何递归数据结构,如不同类型的树等

现在,如果你用一个反同态构建一个递归数据结构,然后用一个反同态使用它,你会得到所谓的hylomorphim。在这种情况下,实际上不需要中间结构。您可以跳过创建和销毁它。这通常被称为


关于
map
:这个函数很有趣,它既是一个反态射又是一个反态射:

  • map
    使用一个列表并生成一些东西;而且
  • map
    生成一个列表,消耗一些东西
因此,您可以查看两个贴图的组合
map f。map g
作为一个变形(
map g
)与一个变形(
map f
)的组合,形成一个hylomorphic。因此,您知道可以通过不创建中间列表来优化(去叶)

具体来说:您可以用两种方式编写
map
,一种是使用
foldr
,另一种是使用
build

mapAna :: (a -> b) -> [a] -> [b]
mapAna f xs = build (mapAna' f xs)

mapAna' :: (a -> b) -> [a] -> (b -> c -> c) -> c -> c
mapAna' f []       cons nil = nil
mapAna' f (x : xs) cons nil = (f x) `cons` (mapAna' f xs cons nil)


mapCata :: (a -> b) -> [a] -> [b]
mapCata f xs = foldr (\x ys -> f x : ys) [] xs

而构图
map f(map g zs)
as
mapCata f(mapAna g zs)
,经过一些简化并应用
foldr c n(build g)==gcn
后,会产生
map(f.g)

,您可能想在理论CS页面上发布这一点,too@blueberryfields:用于研究级TCS,这个问题不是@Yttril:Fold是一种通用运算(数据结构上的每个顺序动作都可以表示为Fold),这表明很少有这样的方程成立。@Giles:是的,这就是为什么我想知道到底有多少优化。据我所知,融合需要更高阶的多态递归,虽然我的语言几乎无法支持单子,但它无法处理融合;(可能我这里的一些术语搞错了。…+1用于流融合论文的引用!没有多态递归。我不知道什么是高阶多态递归。但是,
build
有一个秩2类型(第一个参数上的
forall
)。流融合反过来需要存在类型(步进函数).也许你可以解释一下你想做什么(以及你的设置)?我的设置是我的语言Felix。我主要是在寻找优化。理想情况下,有人会帮助设计一个合适的火种系统,以实现像fusion这样的高级优化。对不起,太简单了:Felix有类型模式,加上一些实现不好的火种,允许实现一些更高的东西,例如Monads..但仅限于类型系统基本上是lambda演算,有产品、函数和类型匹配,但没有变体。如果可以添加变体,我认为它相当于Jay的模式演算的类型化版本。哎哟……折叠在地图上,没想到:)是的,我应该读更多。最近又回到慈善机构。