Functional programming with clojure, avoiding mutable state

时间:2016-04-04 17:33:48

标签: clojure functional-programming state immutability purely-functional

So, my question is about whether I can avoid mutable state in a particular action my program needs to do.

Some context: About a week ago I decided to learn to program in Clojure, to teach myself functional programming. (By day I work as a web developer using mainly C#.

So in my experience the best way to learn a language is to start with a project. I chose to create something that I needed anyway, a small tool to read text snippets out of an XML file and then do some find-and-replacing in other text files (and detecting inconsistencies.

So I'm up to the part where I've parsed the file into a list of maps that I need, and here's the problem: the way I see it, I can pass around my data between functions as much as I want, at some point there's nothing to do for my program. And then when the user clicks a (javax.swing-button, my program will have forgotten everything.

How would a functional programmer solve this?

Possible solutions I came up with:

-Monads. (Great for building complexity but still disappear when the functions stop executing.

-Read the file from disk again everytime the user clicks a button: seems silly.

-Store the contents of my file within my form controls. Seems like cheating (and also just wrong.

-When a file is parsed, create a closure with references to the resulting datastructure, and install this a the new event handler(s) : seems like cheating and just generally a strange (but interesting) thing to try.

Who can tell me if I've identified this correctly as a situation where I can't do without a ^dynamic var?

Any pointers will be greatly appreciated.)))))

Edit: I'm not asking for for code examples, just a yes or no answer would do, and maybe a hint on what to look up next, to the question: is there a way for a clojure program to remember some data it computed, in idle state (until next java event handler gets fired), without using a global variable, atom, ref, or agent?

And the reason I'm asking is that I want to learn to program in a functional style the proper way, and I'm basically checking if I'm not going off track.

Thanks for all the useful responses so far, definitely got tips on books to read, that's always nice.

2 个答案:

答案 0 :(得分:3)

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

That may be true when you are staying within the same paradigm - e.g. imperative programming. No matter how many "functional programming techniques" you already use, the imperative mindset tends to remain. Moving from the imperative mindset to the functional mindset can be quite jarring.

To start changing that mindset start with the basics like Clojure the Brave or Living Clojure; start practicing on 4clojure and Clojure Koans.

Clojure doesn't eliminate mutability but mutability by default - i.e. it forces you to consider whether or not it is absolutely necessary to mutate something to accomplish your objective. Once you determined that mutability is required you have the choice of Vars, Refs, Agents and Atoms - each with its own advantages and drawbacks.

From RxJS is great. So why have I moved on? — Medium in reference to 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.

See also: Teaching Clojure at IBM - Steve Shogren

答案 1 :(得分:0)

特定于Clojure的问题答案几乎肯定不会使用^dynamic,而是使用agentatomrefs

但我相信你的问题更多的是哲学问题而非实际问题? This interview与西蒙佩顿琼斯是我对这个问题最喜欢的解释。纯粹(纯粹的纯粹感觉)功能程序没有副作用,因此是无用的。然而,正如西蒙在采访中所说,功能语言都提供了引入有限的,受控制的副作用的方法,以避免污染程序的纯粹功能方面。 Haskell通过其类型系统(monad,monoids和类别理论)来做到这一点。 Clojure通过代理,原子和refs来做到这一点。榆树是通过信号做到的。 Erlang通过进程和消息队列来完成它。等等...