惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
Martin Fowler
Martin Fowler
I
InfoQ
腾讯CDC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
爱范儿
爱范儿
Microsoft Security Blog
Microsoft Security Blog
Google DeepMind News
Google DeepMind News
D
DataBreaches.Net
云风的 BLOG
云风的 BLOG
F
Fortinet All Blogs
N
Netflix TechBlog - Medium
博客园 - 聂微东
Microsoft Azure Blog
Microsoft Azure Blog
D
Docker
博客园 - 三生石上(FineUI控件)
Y
Y Combinator Blog
博客园 - Franky
Engineering at Meta
Engineering at Meta
B
Blog
罗磊的独立博客
Apple Machine Learning Research
Apple Machine Learning Research
Jina AI
Jina AI
V
Visual Studio Blog

Jiajun的技术笔记

你好,2026! TiDB 源码阅读(六):TiDB Coprocessor 源码解析 性能优化的核心思想 TiDB 源码阅读(五):索引 TiDB 源码阅读(四):AST、逻辑计划、物理计划 CockroachDB Serverless Architecture podman 无故退出 Cursor Control-L (CTRL-L) Keyboard Shortcuts in Terminal Replace docker with podman Using xmonad with xfce4 A RC script for freebsd frpc 自己动手写一个k8s controller AI 会取代你的(编程)岗位吗? 自建DERP服务器提升Tailscale连接速度(使用Nginx转发) 自动升级Docker容器 再读《程序员修炼之道-从小工到专家》 让浏览器下载文件 再读《软件随想录》/《黑客与画家》/《软技能》 HTTP 压力测试中的 Coordinated Omission 2的补码 编程语言中的 context 是什么? flutter macOS 构建出错 Flatpak 使用小记 Golang CAS 操作是怎么实现的 PostgreSQL 当MQ来使用 Clash 结合 工作VPN 的网络设计 使用 PostgreSQL 搭建 JuiceFS PostgreSQL 配置优化和日志分析 有GitHub Copilot?那就可以搭建你的ChatGPT4服务 窗口函数的使用(以PG为例)
foldl 和 foldr 的变换
2016-05-22 · via Jiajun的技术笔记

foldl 和 foldr 的类型签名为:

.. code:: haskell

Prelude> :t foldl
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
Prelude> :t foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

可以看出来他们接受的参数为:一个函数,一个initial value,一个列表, 然后把整个列表变成和列表类型相同的value。举个例子:

.. code:: haskell

foldl (+) 0 [1..5]
-- 展开成
= ((((1 + 2) + 3) + 4) + 5)
= 15

foldr (+) 0 [1..5]
-- 展开成
= (1 + (2 + (3 + (4 + 5))))
= 15

从结果来看foldl和foldr似乎可以相互替换,但并不是这样的,上例结果相同只是因为 加法(+)满足结合律,同样是这么几个数,从左往右加和从右往左加结果是一样的。 但对于减法就不是这样了,我们继续看代码:

.. code:: haskell

Prelude> foldl (-) 0 [1..5]
-15
Prelude> foldr (-) 0 [1..5]
3

那么foldl和foldr长得那么像,能不能互相实现呢?我们来用foldl实现foldr, 首先我们从类型签名看起。

  • foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b

  • foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

可以看出来,首先接受的第一个函数的参数是相反的,所以对于 foldr func init alist 首先要把函数的参数反过来,所以我们用了 flip, foldl (flip func) init alist (flip 的类型为 flip :: (a -> b -> c) -> b -> a -> c )。 但是这还不够,foldl是从左边向右两个两个处理,而foldr是从右向左,我们需要将 alist反转,所以我们用了 reverse,他的类型是 reverse :: [a] -> [a] :

.. code:: haskell

foldr func init alist = foldl (flip func) init (reverse alist)
-- 可以化简成:
foldr func init = (foldl (flip func) init) . reverse

python中的foldl

python中有reduce,作用相当于Haskell中的foldl:

.. code:: python

>>> import operator
>>> from functools import reduce
>>> reduce(operator.add, list(range(1, 6)), 0)
15

参考资料:

.. [#] <https://wiki.haskell.org/Foldr_Foldl_Foldl'>_