3

我正在开发一个使用大爆炸式编程风格的游戏,其中将整个状态定义为单个数据结构,并通过交换单个原子来管理状态更改。

在游戏中,我们不能信任客户端发送的数据,因此服务器必须预测某些动作无效的可能性并加以防范。当一个人编写一个交换世界状态的函数时,它可以从纯粹的开始;但是,必须考虑无效请求的可能性。我相信要在惯用的 Clojure 中实现不愉快的路径,只需抛出异常。所以现在可能是纯函数被副作用异常感染了。也许就是它必须的样子。

(try
  (swap! world update-game) ;possible exception here!
  (catch Exception e
    (>! err-chan e))

我的目标是将副作用推迟到最后一刻。我几乎没有涉足 Haskell 领域,但我知道 Either monad 的概念。当一个人考虑幸福和不幸的道路时,就会明白总有这两种可能性。这让我认为这swap!本身是不够的,因为它忽略了不愉快的道路。这是这个想法的精神:

(swap-either! err-chan world update-game) ;update-game returns either monad

Clojure 社区是否采用了更多功能性的方法来处理异常?

4

1 回答 1

3

在这种情况下,我倾向于采取几种不同的方法。如果在单个位置更新状态,我倾向于使用:

(try
  (swap! world update-game) ;possible exception here!
  (catch Exception e
    (>! err-chan e) 
    world)  ;;  <--- return the world unchanged

或者,如果它设置在很多地方广告一个观察者,将异常抛出回交换的地方!被调用并且不改变状态:

user> (def a (atom 1))
#'user/a
user> (add-watch a :im-a-test (fn [_ _ _ new-state]
                                (if (even? new-state)
                                  (throw (IllegalStateException. "I don't like even numbers")))))
#object[clojure.lang.Atom 0x5c1dc37e {:status :ready, :val 1}]
user> (swap! a + 2)
3
user> (swap! a + 3)
IllegalStateException I don't like even numbers  user/eval108260/fn--108261 (form-init8563497779572341831.clj:2)
于 2015-06-12T22:07:08.330 回答