用纯功能语言保持状态 [英] Keeping State in a Purely Functional Language

查看:64
本文介绍了用纯功能语言保持状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图弄清楚如何做,假设您正在为直流电动机的控制器工作,并希望以用户设定的特定速度使其旋转,

I am trying to figure out how to do the following, assume that your are working on a controller for a DC motor you want to keep it spinning at a certain speed set by the user,



(def set-point (ref {:sp 90}))

(while true
  (let [curr (read-speed)]
    (controller @set-point curr)))


现在,设定点可以随时通过Web应用程序进行更改,我想不出没有引用就可以做到这一点的方法,所以我的问题是功能如何语言处理这种事情? (即使示例在clojure中,我也对一般想法感兴趣。)

Now that set-point can change any time via a web a application, I can't think of a way to do this without using ref, so my question is how functional languages deal with this sort of thing? (even though the example is in clojure I am interested in the general idea.)

推荐答案

这不会回答您的问题,但是我想要展示如何在Clojure中完成这些事情。它可能会帮助某人稍后阅读此书,因此他们认为不必阅读Monad,反应式编程或其他复杂主题即可使用Clojure。

This will not answer your question but I want to show how these things are done in Clojure. It might help someone reading this later so they don't think they have to read up on monads, reactive programming or other "complicated" subjects to use Clojure.

Clojure是不是一种完全的功能语言,在这种情况下,最好暂时搁下纯函数并建模具有身份的系统的固有状态

Clojure is not a purely functional language and in this case it might be a good idea to leave the pure functions aside for a moment and model the inherent state of the system with identities.

在Clojure中,您可能会使用一种引用类型。有多种选择,要知道使用哪一种可能很困难。好消息是它们都支持统一更新模型,因此以后更改引用类型应该很简单。

In Clojure, you would probably use one of the reference types. There are several to choose from and knowing which one to use might be difficult. The good news is they all support the unified update model so changing the reference type later should be pretty straight forward.

我选择了 atom ,但根据您的要求,它可能更适合使用 ref agent

I've chosen an atom but depending on your requirements it might be more appropriate to use a ref or an agent.

电机是程序中的一个标识。它是某些事物的标签,在不同的时间具有不同的值,并且这些值彼此相关(即,电动机的速度)。我在原子上放置了:validator 以确保速度永远不会降至零以下。

The motor is an identity in your program. It is a "label" for some thing that has different values at different times and these values are related to each other (i.e., the speed of the motor). I have put a :validator on the atom to ensure that the speed never drops below zero.

(def motor (atom {:speed 0} :validator (comp not neg? :speed)))

(defn add-speed [n]
  (swap! motor update-in [:speed] + n))

(defn set-speed [n]
  (swap! motor update-in [:speed] (constantly n)))

> (add-speed 10)
> (add-speed -8)
> (add-speed -4) ;; This will not change the state of motor
                 ;; since the speed would drop below zero and
                 ;; the validator does not allow that!
> (:speed @motor)
2
> (set-speed 12)
> (:speed @motor)
12

如果要更改电动机的语义身份,您还有至少两种其他参考类型可供选择。

If you want to change the semantics of the motor identity you have at least two other reference types to choose from.


  • 如果要异步更改电动机的速度,可以使用代理。然后您需要使用 send 更改 swap!。例如,如果调整电动机速度的客户与使用电动机速度的客户不同,因此可以最终更改速度就可以了。

  • If you want to change the speed of the motor asynchronously you would use an agent. Then you need to change swap! with send. This would be useful if, for example, the clients adjusting the motor speed are different from the clients using the motor speed, so that it's fine for the speed to be changed "eventually".

另一种选择是使用 ref ,如果电动机需要与系统中的其他身份协调,则该方法将是适当的。如果选择此引用类型,则将 swap!更改为 alter 。此外,所有状态更改都在具有 dosync 的事务中运行,以确保原子地更新事务中的所有身份。

Another option is to use a ref which would be appropriate if the motor need to coordinate with other identities in your system. If you choose this reference type you change swap! with alter. In addition, all state changes are run in a transaction with dosync to ensure that all identities in the transaction are updated atomically.

在Clojure中不需要单子来建模身份和状态!

Monads are not needed to model identities and state in Clojure!

这篇关于用纯功能语言保持状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆