Как я могу сделать обновляемую карту-функцию с обновляемым condp внутри него? - PullRequest
1 голос
/ 20 февраля 2011

У меня две основные цели:

1.) {:foo (fn ...)} должен быть определен вне функциональной карты таким образом, чтобы вы могли обновлять :foo's (fn ...) (возможно, ссылка, но, возможно, атом)

2.) Случаи condp: "fred", "ethel" должны находиться в структуре, которая также может быть обновлена. Например, если я хочу добавить "lucy" (handle-lucy a b c d) в condp, я бы хотел сделать это, используя отдельную структуру для хранения всех случаев для condp. Проблема в том, что, например, размещение их на карте или векторе означает, что переменные a b message and d недоступны в контексте этой структуры.

Описание: Помогите мне изменить это, чтобы сделать :foo и :bar их собственными функциями, которые живут в #'function-map, которые можно обновлять во время работы программы. Кроме того, помогите мне найти способ взять кейсы для condp и поместить их в собственный обновляемый контейнер.

Резюме 2: Если вы считаете, что то, о чем я прошу, является сумасшедшим, сделайте рефакторинг, как считаете нужным. В основном меня интересует повышение читабельности и доступности.

Это сокращенная версия карты функций, которую я пытаюсь изменить для рефакторинга

(def function-map
  {:foo (fn [{:keys [a b message d]}]
          (let [[command & args] (.split message " ")]
            (condp = command
                "fred" (handle-fred a b @d)
                "ethel" (handle-ethel a b (first args) @d)
                nil)))
   :bar (fn [{:keys [a b c]}]
          (do-something a b c))})

1 Ответ

3 голосов
/ 20 февраля 2011

1) Ваш очевидный выбор здесь - сделать функцию-карту ссылкой / атомом, содержащим карту, ИЛИ сделать значение для каждого ключа ссылкой / атомом, содержащим функцию.Я не могу судить по твоему описанию, которое имеет больше смысла.1 ref / atom проще, но любое изменение карты функций потенциально может создать конфликт транзакций для любого другого изменения.Я предполагаю, что эта карта не меняется постоянно, а только изредка, и в этом случае 1 ref / atom, вероятно, будет достаточно.Атомы для несогласованных синхронных изменений.Ссылки предназначены для согласованного (транзакционного) синхронного изменения.Если вам необходимо изменить несколько функций вместе как часть транзакции или выполнить поведение типа «сравните и установите», используйте ссылку.В противном случае используйте атом.

2) Для части condp мне кажется, что вы хотите динамическое (полиморфное) поведение, основанное на значении.Чтобы получить это, не используйте condp;используйте мультиметод с функцией диспетчеризации, которая использует изменяемое состояние.Это позволит вам динамически добавлять случаи (defmethods) без изменения кода отправки.Если вы хотите «обновить» набор команд после факта, добавьте новый defmethod, когда захотите.Если вы хотите получить доступ к состоянию во время обработки, просто передайте его в определение обработчика.

(defmulti handle-command (fn [command a b message d & args] command))
(defmethod handle-command "fred" [_ a b _ d] (handle-fred a b d))
(defmethod handle-command "ethel" [_ a b _ d [f & _]] (handle-ethel a b f d))

(def function-map
  {:foo (fn [{:keys [a b message d]}]
          (let [[command & args] (.split message " ")]
            (handle-command command a b message @d args)))})

Извинения за опечатки ... на самом деле не пытаясь сделать что-либо из этого в ответ.

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