Использование методов инкапсуляции в стиле C в Clojure? - PullRequest
3 голосов
/ 12 июля 2010

Я работаю над своей первой (нетривиальной) Clojure программой Мне не очень комфортно, когда я объявляю все свои изменчивые состояния глобально Например:

(def next-blocks (atom []))
(def num-next-blocks 1)
(def is-game-over (atom false))
(def user-name (atom (str)))
(def hs-xml (atom nil))

Поскольку я часто использую C на работе, у меня возникла идея использовать общие методы инкапсуляции в стиле C. Обычно он включает в себя объект struct, который передается в качестве первого аргумента любым «функциям-членам», которые работают с ним. См. Например, udev .

Применение этого к Clojure приведет к тому, что функции будут выглядеть так (непроверено):

(defstruct gamestate)

(defn game-new []
  (struct-map gamestate
    :level            (atom 0)
    :score            (atom 0)
    ;etc...
    ))

(def game-get-score [game]
    @(game :score))

(defn game-set-score [game new-score]
  (reset! (game :score) new-score))

(defn game-get-level [game]
  @(game :level))

(defn game-inc-level [game]
  (swap! (game :level) inc))

; etc...

Я думаю, что это определенно будет шагом вперед к глобальным определениям, которые я использую в настоящее время.

Так это рекомендуемый путь? Или есть более стандартный способ Clojure?

Обновление

В настоящее время я использую Clojure 1.1.0.

Ответы [ 3 ]

6 голосов
/ 13 июля 2010

Основная идея функционального программирования состоит в том, что у вас очень мало глобальных переменных, но в основном локальных (см. статью Рича Хики о состоянии и идентичности ).Написание игры в этой парадигме может быть сложной задачей, я бы порекомендовал этот пост о функциональном программировании для игр (хотя примеры приведены на Erlang).

Я не знаю, какого родаигры, которую вы хотите реализовать.Вот фрагмент кода, улучшающий то, что я бы сделал с локальными переменными.

(defn play-game [name score blocks]
  (let [level (start-mission (:level score) blocks)]
    (if level
      (assoc score :level level)
      score)))

(defn the-whole-game []
  (let [name (ask-username)
        score (or (load-score name) {:level 0, :score 0}]
    (when-let [new-score (play-game name score [])]
       (save-score name new-score))))

Возможно, вы захотите проверить другой клон тетриса в clojure , хотя он использует opengl.

4 голосов
/ 12 июля 2010

В моей игре Clojure я использую один атом, содержащий карту, для хранения всего изменяемого состояния игры Это включает в себя определенные элементы состояния пользовательского интерфейса.

В настоящее время это определяется следующим образом:

(def state 
  (atom 
    {:game (gamefactory/make-game)
     :scroll [0 0]
     :mouseover [0 0]
     :command-state nil
     :commands (clojure.lang.PersistentQueue/EMPTY)
     :animations {}
     :player-id nil}))

Эта модель работает очень хорошо для меня. Вы можете легко получить доступ к элементам состояния напрямую, например, (: game @state) или, альтернативно, определите функции доступа.

2 голосов
/ 12 июля 2010

Вы можете использовать карту для эмуляции структуры в стиле C. Вы также можете использовать (если вы используете v1.2), вы можете использовать deftype / defrecord.

(defn get-game-score [game]
   (:score game))

(defn set-game-store [game new-score]
   (assoc game :score new-score))

Я бы порекомендовал использовать карту esp. так как они могут быть легко использованы в мультиметодах.
Самая важная вещь, о которой следует помнить, это то, что вам не следует думать об использовании переменных в clojure так же, как вы делаете это в C, и атомы не совпадают с переменными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...