Какова функциональная версия вложенного теста? - PullRequest
0 голосов
/ 28 сентября 2018

Я конвертирую некоторый код C ++ в Clojure и хочу вернуть график g с добавлением нескольких ребер.Я передаю число вершин, график и тестовый предикат (например, функцию, которая может зависеть от i, j, случайность, ...) примерно так:

(defn addSomeEdges [v g test-p]
  (doseq [i (range v)]
    (doseq [j (range (dec i))] 
      (if test-p 
          (add-edges g [i j] )
          )))
  g)

проблемаКонечно, (add-edges) возвращает новый g.Как мне записать этот обновленный график, используя лучшие практики Clojure, пожалуйста?Это кажется таким простым и естественным в C ++.

Ответы [ 2 ]

0 голосов
/ 28 сентября 2018

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

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

, который можно записать с помощью reduce

user> (defn add-edge [g i j]
        (assoc g i j))
#'user/add-edge

user> (add-edge {1 2} 2 1)
{1 2, 2 1}

user> (defn addSomeEdges [v g test-p]
        (reduce (fn [graph [i j]]        ;; this takes the current graph, the points,
                  (if (test-p graph i j) ;; decides if the edge should be created.
                    (add-edge graph i j) ;; and returns the next graph
                    graph))              ;; or returns the graph unchanged.
                g  ;; This is the initial graph
                (for [i (range v)    
                      j (range (dec i))]
                  [i j])))  ;; this generates the candidate edges to check.
#'user/addSomeEdges

, и давайте запустим его!

user> (addSomeEdges 4 {1 2} (fn [g i j] (rand-nth [true false])))
{1 2, 2 0}
user> (addSomeEdges 4 {1 2} (fn [g i j] (rand-nth [true false])))
{1 2, 3 0}
user> (addSomeEdges 4 {1 2} (fn [g i j] (rand-nth [true false])))
{1 2, 2 0, 3 1} 

Когда вы подумаете одругие тесты, вы можете связать эти вызовы вместе:

user> (as-> {1 2} g
        (addSomeEdges 4 g (fn [g i j] (rand-nth [true false])))
        (addSomeEdges 7 g (fn [g i j] (< i j)))
        (addSomeEdges 9 g (fn [g i j] (contains? (set (keys g)) j))))
{1 2, 3 1, 4 1, 5 3, 6 4, 7 5, 8 6}
0 голосов
/ 28 сентября 2018

Существует более одного решения.Однако иногда, когда у вас есть принципиально изменяемая / императивная проблема, вы должны просто использовать изменяемое / императивное решение:

; simplest version using mutation
(defn addSomeEdges [v g test-p]
  (let [g-local (atom g)]
    (doseq [i (range v)]
      (doseq [j (range (dec i))]
        (when (test-p i j ...)  ; what other args does this need?
          (swap! g-local add-edges [i j]))))
    @g-local))

Я был немного неуверен в семантике test-p, так что эта часть можетнеобходимо уточнение.

Обратите внимание, что swap! будет вызывать add-edges примерно так:

(add-edges <curr val of g-local> [i j])

См. Таблицу Clojure & ClojureDocs.org для получения дополнительной информации.

...