编程与软件工程lihaoyi.com
函数式编程到底在讲什么?
What's Functional Programming All About?
2017 — 2024,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
Li Haoyi 撰写的函数式编程入门长文,核心观点是 FP 的本质在于“以数据流而非控制流来思考程序”:让所有依赖显式传入、避免隐藏的状态和副作用。文章用图示和例子说明这种风格如何带来更好的可测试性、可组合性和可推理性,并强调 FP 是一种可在任何语言中实践的风格,而非某个语言的专利。
为什么经久不衰:它把函数式编程从语言特性之争还原为一种普适的思维方式,2017 年和 2024 年两度登上首页,说明这种视角至今仍是理解 FP 最清晰的入门路径。
HN 评论精选
从定义出发系统阐述 FP 的好处:易推理、易测试、可组合,且性能并不吃亏
函数式编程意味着程序由函数组成:函数只依赖输入参数,其效果就是返回值,因此没有副作用。函数是很好的抽象,看输入输出就能掌握完整数据流,易于推理;没有副作用就没有意外干扰;函数只依赖参数,容易测试;相同输入必然相同输出;也因此天然可组合。虽然某些任务修改全局状态更高效,但 FP 未必慢:无副作用使并行化更容易,局部状态让编译器能更激进地优化。
_ph_查看英文原文
Functional programming means, that your program is composed out of functions. A function only depends on its input parameters and the effect of applying a function is the returned function result. By this definition, functions don't have side effects. Why do functions and functional programming matter? - Functions are a very nice abstraction. Looking at the input and output values gives you the complete information about the data flow. This makes functions very easy to reason about. - With the absence of side effects, you also have no unintended side effects, which plague all code which modifies state. - Functions are easily testable, they do not depend on an environment but just the function parameters. - For the same input a function necessarily always returns the same result, this also makes reasoning about a programs behavior easier. - As a consequence that they only depend on their inputs, functions usually are very composeable. While for certain tasks, modifying a global state can be the most efficient way of performing a computation, functional programming does not have to be slow, and in many cases the resulting program might even be faster. There are several reasons for this: - With the lack of side-effects, functional programs can be relatively easy parallelized. - With only local state involved, compilers can optimize the code inside functions more aggressively. There are pure functional languages, but most modern languages allow you to write your program in a functional style. So it is possible to mix functional with object oriented programming.
认同“数据流”这一核心定义,并指出 FP 与不可变性互为表里、任何语言皆可实践
“函数式编程的核心是思考数据流而非控制流”——我很喜欢这个说法。FP 本质上是不可变性的副产品:把所有依赖显式传入、所有结果显式返回,而不是依赖隐式输入输出。显式依赖会迫使你写不可变代码,反之亦然,这是数据流这枚硬币的两面。而且聚焦数据流说明任何语言都能做 FP,在 C 甚至汇编里也能实践,只是需要更多自律。
dahart查看英文原文
> The core of Functional Programming is thinking about data-flow rather than control-flow I've spent a small amount of time trying to convince people that FP is a byproduct of immutability and not much else. But I like this description better than that. I like that it captures the idea of dependencies. Data flow, and FP, are about explicitly passing all the required dependencies into any step in the process, and getting back all the results - as opposed to having any implicit inputs or output. Making all dependencies explicit will force you into writing immutable code, and likewise writing exclusively with immutable data and functions that dont have side-effects will automatically make you spit out code with explicit dependencies as a byproduct. These are two sides of the data-flow coin. I also like that the focus on data-flow makes it clear you can do FP in any language. Some languages definitely help you, but you absolutely can practice data-flow over control-flow in C and assembly almost as easily as python. It's just tempting not to when you don't have to, being more strict about FP takes more self control.
补充技术细节:框图即语法树,表达式嵌套天然表达了依赖关系
很好的综述。文中那个框图其实就是一棵树,恰好是“大表达式”版本的语法树。大表达式的好处还在于:即使是硬核命令式程序员也避免依赖参数的求值顺序(如 f(x, y) 中 x、y 谁先求值在 C 里是未定义的),所以依赖关系由嵌套结构清晰表达,相邻表达式可视为相互独立。
chriswarbo查看英文原文
A very nice overview; whilst the author is right about having to 'linearise' the block diagram into lines of text, it might be worth mentioning that the diagram is a perfectly valid way of drawing a tree, and that tree is (as far as I can tell) exactly the syntax tree of the 'big expression' (the version which doesn't put intermediate values into variables)! Another nice point about the 'big expression' version: even hardcore imperative programmers tend to avoid relying on "horizontal" order of execution, e.g. in `f(x, y)` it's frowned upon to rely on either `x` or `y` being evaluated first; the order is even undefined in some languages (e.g. C). Hence the dependencies are clear from the nesting, whilst adjacent expressions can be assumed to be independent. FYI I wrote up my own advice at http://chriswarbo.net/blog/2015-01-18-learning_functional_programming.html which echoes some of the points in this article (e.g. FP is a style applicable to many languages; there's a spectrum from "less functional" to "more functional", and it's fine to pick and choose for your situation; etc.)
实践者现身说法:函数式风格 + 全面单元测试带来极高的可靠性和信心
我喜欢用函数式风格写 Python:每个函数都是单向的,相同输入永远相同输出;为每个函数建单元测试和路径测试,覆盖所有极端输入;然后把函数逐层组合成更大的函数并同样测试。修改的影响总是局部的,我对测试充满信心。每次运行程序都完美无缺、从不崩溃。相比之下,面向对象要维护外部状态,方法之间互相修改变量……
blackrock查看英文原文
I love programming in a functional-style in Python. I create one-way functions. Every input will always give the same output. Then I build out the test harness for that function, to unit test the function, and pathway test it. So I make sure that I have automated tests to capture every single extreme that can go into the function. I do this for every single function created. Then I string together one function into another, and I put that into its own function. And I unit test that larger function. Then sometimes, I even put those 2nd level functions, into more functions. And I unit test that as well. In the end, I just have a function that calls a function, that calls a function, and so forth. The rabbit hole just goes deeper and deeper. If I ever need to enhance a function, then I make my changes, add more unit tests, and re-execute it. The impact is always local, and I have full confidence in my unit tests and pathway tests. I'm always incredibly amazed when I execute the program, and it works flawlessly, every time. I keep iterating through the development cycle this way. And every version checked in, is fully tested, very accurate, with detailed test logs captured, and most importantly, it does not crash. It's beautiful. With Object-oriented programming, I have to maintain an external state. This is like modifying a global variable within your object. Your methods have to load and manipulate an external variable. And then another method will modify it later. However, I do like the organization and hiding ability of OOP. So in the end, I just make all my functions as a functional-style, one-way function. And my methods are just wrappers around it. My main complaint about Python, is that it's just slow. I wish it had a compile to binary feature built in. Although, I get around that with my heavy unit tests, but some coding mistakes can be easily caught during compile time.
历次讨论
同类还值得读
开源应用架构
The Architecture of Open Source Applications
《开源软件架构》(AOSA)是一本在线免费书,邀请知名开源项目的作者亲自剖析其内部设计,涵盖 SQLAlchemy、LLVM、Audacity、Apache、Bash 等系统。
编程与软件工程上首页 9 次 · 2011–2024aosabook.org编辑精选编程语言简史:简短、不完整且多半错误
A Brief, Incomplete, and Mostly Wrong History of Programming Languages
一篇以戏谑、故意不准确的方式回顾编程语言史的博客文章,用夸张轶事和讽刺定义串起 Lisp、C、C++、Java、JavaScript、PHP 等语言。
编程与软件工程上首页 8 次 · 2009–2021james-iry.blogspot.comSQLite 是如何测试的
How SQLite is tested
SQLite 官方文档页,系统介绍 SQLite 的测试体系:多种测试方法(TCL 测试、模糊测试、回归测试、静态分析等)和海量测试用例,展示了这个小型开源项目如何靠极致测试获得…
编程与软件工程上首页 8 次 · 2009–2025sqlite.org编辑精选高级编程语言(2009)
Advanced programming languages (2009)
Matt Might 的经典文章,按用途推荐“高级编程语言”:如果追求就业就选主流语言,如果追求表达力、学术研究或创业,则推荐 Haskell、OCaml、Scala 等函数式语…
编程与软件工程上首页 8 次 · 2009–2022matt.might.net我的 Forth 与栈机器经历
Yosefk - My history with Forth & stack machines
作者以亲身经历回顾了使用 Forth 语言和栈式机器的历程:既赞叹其简洁优雅、代码量小、可自举的优点,也坦率指出栈操作在实际编程中的痛苦,以及 Forth 社区文化中的问题。
编程与软件工程上首页 8 次 · 2010–2024yosefk.com编辑精选