函数式编程的非数字用例?

时间:2008-12-19 17:51:05

标签: scala f# functional-programming

我刚读完一本关于scala的书。令我震惊的是,整本书中的每一个例子都是某种形式的数字。

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

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

18 个答案:

答案 0 :(得分:45)

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

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

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

  • 一个Join类,一个Joins集合类
  • WhereClause类,WhereClauses集合类
  • 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行,大约100行左右的.fs文件组成,用于实现词法分析器/解析器,并在我的一天中耗费了几个小时进行测试。

说真的,在F#中编写应用程序的这一部分感觉就像是作弊,这简直太容易了。

答案 1 :(得分:10)

答案 2 :(得分:7)

函数式编程是一种范式,如过程/结构化,面向对象,以及泛型/模板化编程。这是完美的,所以你可以做任何你想做的事情。

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

答案 3 :(得分:5)

您可能有兴趣与Erlang的创作者一起收听软件工程广播的这一集,Erlang是在为爱立信工作时开发的。

http://www.se-radio.net/podcast/2008-03/episode-89-joe-armstrong-erlang

答案 4 :(得分:4)

为你准备另一个:

我参与了一系列新型企业级金融产品原型设计的最初阶段,这些产品适用于中小型银行,地方政府,证券交易所等。您可能正在考虑“哦,财务代码,你必须做很多数学“ - 实际上,没有。这些产品旨在实现高度可定制,并允许用户在应用程序的关键点注入业务规则。

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

答案 5 :(得分:3)

结帐Text Processing in Python。本书从一些简单但充满动力的例子开始,其中函数式编程技术使代码更易于阅读,更可能是正确的。

答案 6 :(得分:3)

"Getting Started with Erlang"有一个广泛的客户端/服务器示例(从1.3.5节开始),可能符合您的需求。

答案 7 :(得分:3)

我使用的功能越多,我就越喜欢它。考虑来自another question的这个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中有很多的生成器。一旦你习惯了它,使用列表理解代替循环很容易理解,并且不太可能有bug(你不会被“一个”错误。)

答案 8 :(得分:2)

关于函数式编程的很多书都使用“数值编程”进行教学,但也有例外。

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

Real World Haskell在整本书中并没有任何特定的载体,但有几章涵盖了以功能方式编写“真实”程序。

答案 9 :(得分:2)

现在,我甚至不会考虑用非功能性语言(广义上讲)编写DSL词法分析器/解析器。 ADT和模式匹配使它变得更加容易。

答案 10 :(得分:2)

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

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

答案 11 :(得分:1)

选中“Purely functional data structures”(和here's启发该书的博士论文。)

它们展示了如何以纯功能(无副作用)语言创建标准数据结构。然后,您可以使用它们对任何内容进行编程。

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

答案 12 :(得分:1)

模式匹配也是功能编程发光的地方,使其在生物信息学等领域非常有用。

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

答案 13 :(得分:1)

弥合算法差距:段落格式化的线性时间功能程序(1997)
      作者:Oege De Moor,Jeremy Gibbons       http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.33.7923

在TkGofer(1997)中构建图形范式,作者:Koen Claessen,Ton Vullinghs,Erik Meijer http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.38.5525

使用Gert Florijn的功能解析器(1994)建模办公流程 http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.19.1307

答案 14 :(得分:1)

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

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

答案 15 :(得分:1)

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

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

答案 16 :(得分:1)

Ted Neward撰写了一篇关于Scala的10篇文章,针对Java程序员,最后编写了一篇用Scala编写DSL的文章。这个特殊的DSL实际上是一个数字计算器,但这不是它的有趣之处,它是DSL可以用函数式语言轻松组装的方式

Part1

Part2

Part3

答案 17 :(得分:0)

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