我刚读完一本关于 scala 的书。令我印象深刻的是,整本书中的每一个例子都是以某种形式呈现的数字。
像许多程序员一样,我使用的唯一数学是离散数学和组合数学,通常这不是我以明确方式编程的数学。我真的错过了一些关于常规 oo 算法的功能替代/补充的引人注目的例子。
函数式编程有哪些非数字用例?
我刚读完一本关于 scala 的书。令我印象深刻的是,整本书中的每一个例子都是以某种形式呈现的数字。
像许多程序员一样,我使用的唯一数学是离散数学和组合数学,通常这不是我以明确方式编程的数学。我真的错过了一些关于常规 oo 算法的功能替代/补充的引人注目的例子。
函数式编程有哪些非数字用例?
我的公司要求我编写一个自定义应用程序,允许用户对平面文件数据库执行临时查询。这个应用程序的用户是典型的乔商人类型。他们不是程序员,他们在生活中不太可能见过 SQL 语句。
因此,我的任务是开发一个友好的用户界面,允许用户选择列、表、条件等来构建查询。这是具有挑战性的,因为我可以在 UI 中表示 SQL 语句,而无需先在内存中创建它的抽象表示。
第一次迭代是用 C# 编写的。我创建了一个装载类来表示 SQL 语句的抽象语法,这导致了一个非常麻烦的对象模型:
将 SqlStatement 实例转换为字符串是非常痛苦、丑陋和错误的。将相反的方向从字符串转移到 SqlStatement 更糟糕,因为它使用大量的正则表达式和字符串操作分解了 SQL 字符串的各个部分。
我拼凑了这个系统,制作了一个可以工作的应用程序,但我对它不是很满意。当应用程序的业务需求发生变化时,我尤其没有发生这种情况,这迫使我重新审视我的 C# 代码。
作为一个实验,我用 F# 重写了我的 SqlStatement 并将其表示为一个联合:
type dir = Asc | Desc
type op = Eq | Gt | Gte | Lt | Lte
type join = Inner | Left | Right
type sqlStatement =
| SelectedColumns of string list
| Joins of (string * join) list
| Wheres of (string * op * string) list
| OrderBys of (string * dir) list
type query = SelectedColumns * Joins * Wheres * OrderBys
那少量的代码替换了几百行 C# 和十几个类。更重要的是,模式匹配简化了将抽象表示转换为 SQL 字符串所需的过程。
有趣的部分是使用 fslex/fsyacc 将 SQL 字符串转换回查询对象。
如果我没记错的话,最初的 C# 代码总共有 600 行,大约有十几个类,很多乱七八糟的正则表达式,并且需要两天的时间来编写和测试。相比之下,F# 代码由一个大约 40 行的 .fs 文件组成,大约 100 行来实现词法分析器/解析器,并且花费了我一天中的几个小时来测试。
说真的,用 F# 编写应用程序的这一部分感觉就像在作弊,就是这么简单。
我们使用 Haskell 实现了一种特定领域的语言,用于描述、定价和监控奇异衍生品。
函数式编程是一种范式,类似于过程/结构化、面向对象和通用/模板化编程。它是图灵完备的,所以你可以做任何你想做的事情。
除了数学和科学之外,它还使解析器组合器、人工智能、并发、动态评估、协同例程、延续、简洁符号(更快的大脑到键盘到文本文件的循环和更少的代码维护)变得更容易、强类型参数化(参见 Haskell 的代数类型)和动态自我反思(例如,带有 REPL 的简约元循环解释器)。
再给你一个:
我参与了为中小型银行、地方政府、证券交易所等设计一套新的企业级金融产品原型的早期阶段。你可能在想“哦,金融代码,你必须做很多数学运算”——实际上,不。这些产品旨在高度可定制,并允许用户在应用程序的战略点注入业务规则。
我们使用 F# 来表示和解释业务规则。举一个简单的例子,让我们编写一些用于检查处理的代码,我们可能会编写如下规则:
type condition =
| Test of string
| And of condition * condition
| Or of condition * condition
| Not of condition
type transactionWorkflow =
| Reject
| Approve
| AdministratorOverride of string
| If of condition * transactionWorkflow list
(* condition, true condition *)
| IfElse of condition * transactionWorkflow list * transactionWorkflow list
(* condition, true condition, false condition *)
| AttachForms of string list
使用一个特殊的应用程序,用户可以编写一些由上述结构表示的业务规则。例如:
let checkProcessingWorkflow =
[If(Test("account doesn't exist")
,[AdministratorOverride("Account doesn't exist. Continue?");
AttachForms ["40808A - Null Account Deposit"]]
);
If(Test("deposit > 10000")
,[
If(And(Test("account created within 3 months")
,Test("out of country check"))
,[Reject]);
IfElse(Test("account state = TX")
,[AttachForms ["16A"; "16B"]]
,[AttachForms ["1018"]]
)
]
);
Approve
]
因此,我们不是编写一个业务规则引擎来管理它们,而是将某些流程作为一种由 F# 解释的非常小的领域特定语言来处理。我希望这种方法能够让我们设计非常简单的业务可读 DSL,而无需检测冲突规则。
当然,上面的所有内容都只是概念代码,我们甚至还处于对我们的规则系统之一进行原型设计的早期阶段。我们使用 F# 而不是 Java 或 C# 有一个特殊原因:模式匹配。
“Erlang 入门”有一个广泛的客户端/服务器示例(从第 1.3.5 节开始)可能适合您的需要。
我越是使用功能性风格,我就越喜欢它。考虑另一个问题的这个 Python 片段:
>>> testlist
[1, 2, 3, 5, 3, 1, 2, 1, 6]
>>> [i for i,x in enumerate(testlist) if x == 1]
[0, 5, 7]
诚然,这或多或少是一个数学陈述,但Python 中有很多生成器。一旦你习惯了它,使用列表推导代替循环既容易理解,也不太可能出现错误(你不会“被一个”错误所困扰。)
确实很多函数式编程的书都是用“数值编程”来教的,但也有例外。
Haskell School of Expression是一本关于 Haskell 的初学者书籍,它使用多媒体作为教学工具。
真实世界的 Haskell并没有真正贯穿整本书,但有几章涵盖了以函数式风格编写“真实”程序。
这些天来,我什至不会考虑用非功能性语言(广义上的术语)编写 DSL 词法分析器/解析器。ADT 和模式匹配使它变得如此容易。
非常有趣的问题,因为我认为我是唯一一个为数字编写函数式编程书籍的作者!
函数式编程在历史上更常用于元编程,这意味着编写操作其他程序的程序。这包括解释器和编译器(例如用于 DSL)以及更深奥的应用程序,例如定理证明器(Coq、Isabelle)和术语重写系统(例如,计算机代数系统,如 Mathematica)。元语言 (ML) 系列语言就是为此专门设计的。
模式匹配也是函数式编程大放异彩的地方,使其在生物信息学等领域非常有用。
然而,鉴于我们今天拥有出色的编译器,函数式编程几乎无处不在。
弥合算法差距:用于段落格式化的线性时间函数程序(1997 年)
,由 Oege De Moor、Jeremy Gibbons
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.33.7923
Koen Claessen、Ton Vullinghs、Erik Meijer 在 TkGofer (1997) 中构建图形范式 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.38.5525
使用功能解析器建模办公流程(1994),Gert Florijn
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.19.1307
我能给出的最好的具体例子是StringTemplate,一个在 ANTLR 解析器生成器中使用的模板引擎(在许多其他地方)。
在一篇关于 StringTemplate 的设计和开发的论文中,Terence Parr 写道,他最初对函数式编程持怀疑态度,当他意识到 StringTemplate 本质上是一种用于生成文本的函数式语言时,他自嘲地笑了笑。
对于那些认为 LISP 是一种函数式编程语言的人来说,那里有一个用 common lisp 编写的 http 服务器,在 1994 年的一篇论文中介绍,并且仍在 2006 年开发:
对于更现代的东西,你可能想问谷歌“haskell web server”,你可能会发现一些有趣的例子。一个引导我找到这个网站:http ://code.haskell.org/ 。
LINQ 从函数式编程中获得了很多线索。看看如何实现任意 LINQ 提供程序可能会为您提供一些实用的见解。