27

我刚读完一本关于 scala 的书。令我印象深刻的是,整本书中的每一个例子都是以某种形式呈现的数字。

像许多程序员一样,我使用的唯一数学是离散数学和组合数学,通常这不是我以明确方式编程的数学。我真的错过了一些关于常规 oo 算法的功能替代/补充的引人注目的例子。

函数式编程有哪些非数字用例?

4

16 回答 16

48

我的公司要求我编写一个自定义应用程序,允许用户对平面文件数据库执行临时查询。这个应用程序的用户是典型的乔商人类型。他们不是程序员,他们在生活中不太可能见过 SQL 语句。

因此,我的任务是开发一个友好的用户界面,允许用户选择列、表、条件等来构建查询。这是具有挑战性的,因为我可以在 UI 中表示 SQL 语句,而无需先在内存中创建它的抽象表示。

第一次迭代是用 C# 编写的。我创建了一个装载类来表示 SQL 语句的抽象语法,这导致了一个非常麻烦的对象模型:

  • 一个 Join 类,一个 Joins 集合类
  • 一个 WhereClause 类,一个 WhereClause 集合类
  • 一个 SelectedColumn 类,SelectedColumns 集合类
  • 一个 OrderBy 类,OrderBy 集合集合类
  • 将所有上述类组合在一起的 SqlStatement 类

将 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# 编写应用程序的这一部分感觉就像在作弊,就是这么简单。

于 2008-12-19T19:38:22.347 回答
10

我们使用 Haskell 实现了一种特定领域的语言,用于描述、定价和监控奇异衍生品

于 2008-12-19T18:41:53.350 回答
7

函数式编程是一种范式,类似于过程/结构化、面向对象和通用/模板化编程。它是图灵完备的,所以你可以做任何你想做的事情。

除了数学和科学之外,它还使解析器组合器、人工智能、并发、动态评估、协同例程、延续、简洁符号(更快的大脑到键盘到文本文件的循环和更少的代码维护)变得更容易、强类型参数化(参见 Haskell 的代数类型)和动态自我反思(例如,带有 REPL 的简约元循环解释器)。

于 2008-12-19T18:22:04.760 回答
5

再给你一个:

我参与了为中小型银行、地方政府、证券交易所等设计一套新的企业级金融产品原型的早期阶段。你可能在想“哦,金融代码,你必须做很多数学运算”——实际上,不。这些产品旨在高度可定制,并允许用户在应用程序的战略点注入业务规则。

我们使用 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# 有一个特殊原因:模式匹配。

于 2009-06-05T15:43:53.593 回答
3

“Erlang 入门”有一个广泛的客户端/服务器示例(从第 1.3.5 节开始)可能适合您的需要。

于 2008-12-19T18:37:29.410 回答
3

我越是使用功能性风格,我就越喜欢它。考虑另一个问题的这个 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 中有很多生成器。一旦你习惯了它,使用列表推导代替循环既容易理解,也不太可能出现错误(你不会“被一个”错误所困扰。)

于 2008-12-19T18:39:17.707 回答
2

确实很多函数式编程的书都是用“数值编程”来教的,但也有例外。

Haskell School of Expression是一本关于 Haskell 的初学者书籍,它使用多媒体作为教学工具。

真实世界的 Haskell并没有真正贯穿整本书,但有几章涵盖了以函数式风格编写“真实”程序。

于 2008-12-20T15:41:07.817 回答
2

这些天来,我什至不会考虑用非功能性语言(广义上的术语)编写 DSL 词法分析器/解析器。ADT 和模式匹配使它变得如此容易。

于 2009-07-15T07:36:05.453 回答
2

非常有趣的问题,因为我认为我是唯一一个为数字编写函数式编程书籍的作者!

函数式编程在历史上更常用于元编程,这意味着编写操作其他程序的程序。这包括解释器和编译器(例如用于 DSL)以及更深奥的应用程序,例如定理证明器(Coq、Isabelle)和术语重写系统(例如,计算机代数系统,如 Mathematica)。元语言 (ML) 系列语言就是为此专门设计的。

于 2010-07-01T22:00:58.937 回答
1

模式匹配也是函数式编程大放异彩的地方,使其在生物信息学等领域非常有用。

然而,鉴于我们今天拥有出色的编译器,函数式编程几乎无处不在。

于 2008-12-19T17:52:59.220 回答
1

检查“纯功能数据结构”(是启发本书的博士论文)。

它们展示了如何用纯函数式(无副作用)语言创建标准数据结构。然后,您可以使用它们来编程任何东西。

免责声明:我在这里拉阿特伍德,我几乎没有读过这本书的几篇评论并浏览了这篇论文,它在我的待读清单上。

于 2008-12-19T18:18:01.680 回答
1

弥合算法差距:用于段落格式化的线性时间函数程序(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

于 2008-12-27T03:56:49.167 回答
1

我能给出的最好的具体例子是StringTemplate,一个在 ANTLR 解析器生成器中使用的模板引擎(在许多其他地方)。

在一篇关于 StringTemplate 的设计和开发的论文中,Terence Parr 写道,他最初对函数式编程持怀疑态度,当他意识到 StringTemplate 本质上是一种用于生成文本的函数式语言时,他自嘲地笑了笑。

于 2008-12-27T05:41:52.450 回答
1

对于那些认为 LISP 是一种函数式编程语言的人来说,那里有一个用 common lisp 编写的 http 服务器,在 1994 年的一篇论文中介绍,并且仍在 2006 年开发:

对于更现代的东西,你可能想问谷歌“haskell web server”,你可能会发现一些有趣的例子。一个引导我找到这个网站:http ://code.haskell.org/ 。

于 2009-07-15T06:59:24.857 回答
1

Ted Neward 写了一篇关于 Scala 的 10 部分文章,针对 Java 程序员,该系列文章以在 Scala 中编写 DSL 结束。这个特殊的 DSL 实际上是一个数字计算器,但这不是它的有趣之处,它是 DSL 可以很容易地用函数式语言组装的方式

第1部分

第2部分

第三部分

于 2009-07-15T07:44:35.390 回答
0

LINQ 从函数式编程中获得了很多线索。看看如何实现任意 LINQ 提供程序可能会为您提供一些实用的见解。

于 2008-12-19T18:05:12.470 回答