使用 clojure 进行函数式编程,避免可变状态

Functional programming with clojure, avoiding mutable state

所以,我的问题是关于我是否可以在我的程序需要执行的特定操作中避免可变状态。

一些背景:大约一周前,我决定学习用 Clojure 编程,自学函数式编程。 (白天我是一名主要使用 C# 的 Web 开发人员。

所以根据我的经验,学习一门语言的最好方法是从一个项目开始。我选择创建一些我需要的东西,一个小工具,用于从 XML 文件中读取文本片段,然后在其他文本文件中进行一些查找和替换(并检测不一致。

所以我已经完成了将文件解析为我需要的地图列表的部分,这就是问题所在:在我看来,我可以尽可能多地在函数之间传递我的数据如我所愿,在某些时候我的程序无事可做。然后当用户单击 (javax.swing-按钮时,我的程序将忘记所有内容。

函数式程序员如何解决这个问题?

我想到的可能的解决方案:

-单子。 (非常适合构建复杂性,但当函数停止执行时仍然会消失。

-每次用户单击按钮时再次从磁盘读取文件:看起来很傻。

-将我的文件内容存储在我的表单控件中。看起来像作弊(而且也是错误的。

-解析文件时,创建一个引用结果数据结构的闭包,并将其安装为新的事件处理程序:似乎是在作弊,而且通常是一种奇怪(但有趣)的尝试。

谁能告诉我如果我已经正确地识别出这是一种我不能没有 ^dynamic var 的情况?

任何指点将不胜感激。)))))

编辑:我不是要代码示例,只是回答是或否就可以了,也许还可以提示下一步要查找的问题: 有没有办法让 clojure 程序在空闲状态下记住它计算的一些数据(直到下一个 java 事件处理程序被触发),而不使用全局变量、atom、ref 或代理?

我问的原因是我想学习以正确的方式以函数式风格编程,我基本上是在检查我是否没有偏离轨道。

感谢到目前为止所有有用的回复,绝对有关于书籍阅读的提示,这总是很好。

So in my experience the best way to learn a language is to start with a project.

当您处于同一范式内时,这可能是正确的 - 例如命令式编程。无论您已经使用了多少 "functional programming techniques",命令式思维方式 往往会保留下来。从 命令式思维模式 转变为 功能性思维模式 可能会很不协调。

要开始改变这种心态,请从 Clojure the Brave or Living Clojure; start practicing on 4clojure and Clojure Koans 等基础知识开始。

Clojure 不会消除可变性,但 默认情况下的可变性 - 即它迫使您考虑是否绝对有必要改变某些东西来完成您的 objective .一旦确定需要可变性,您就可以选择 Vars, Refs, Agents and Atoms - 每个都有自己的优点和缺点。

来自 RxJS is great. So why have I moved on? — Medium 对 ClojureScript 的引用:

To be fair it’s really hard compared to learning another OO language. The learning curve is steep. For the first month I constantly felt like I was on a trip to Japan where I couldn’t read or write or speak and had to rely on grunting and pointing.

另请参阅:Teaching Clojure at IBM - Steve Shogren

您问题的 Clojure 特定答案几乎肯定不是使用 ^dynamic,而是使用 agent, an atom, or refs.

但我认为您的问题更多是哲学问题而不是实际问题? This interview with Simon Peyton Jones 是我对这个问题最喜欢的解释。纯(从最纯粹的意义上来说)函数式程序没有副作用,因此是无用的。然而,正如西蒙在采访中所说,函数式语言都提供了引入有限的、受控的副作用的方法,以避免污染程序的纯函数方面。 Haskell 通过其类型系统(monads、monoids 和范畴论)做到这一点。 Clojure 通过代理、原子和引用来做到这一点。 Elm 通过信号来完成。 Erlang 通过进程和消息队列来完成。等等...