2014-09-02 5 views
2

Я хочу выполнить определенное количество времени определенной операции (например, генерации племени). Каждый раз, когда я хотел бы использовать вывод предыдущей итерации в качестве ввода следующего.Clojure: Выполнение операции n раз с использованием вывода в качестве ввода следующей операции (a-la reduce)

Я достигаю этого, выполняя фиктивный снимок по набору из n элементов, тогда я рассматриваю только аккумулятор и выбрасываю элемент из коллекции.

(defn generate-game [world n-tribes] 
    (let [ game (create-game world) 
     game (reduce (fn [acc, _] (:game (generate-tribe acc))) game (repeat n-tribes :just_something))] 
    game)) 

Я предполагаю, что есть намного лучший способ сделать это. Можете ли вы помочь мне найти его?

+0

Iterate - это то, что я искал. Окончательное решение немного отличается, потому что gener-tribe возвращает карту, содержащую игру (в ней также содержится племя генерации). Для меня окончательное решения: '' ' (defn генерировать-игры [мир н-племена] (пусть [игра (создание-игрового мир) игры (NTH (итерационные # (: игра (генерировать -tribe%)) game) n-tribes: just_something)] игра)) '' ' –

ответ

1

Метод, используемый в этом вопросе, это хорошо, но использовать диапазон вместо этого

(defn generate-game [world n-tribes] 
    (reduce (fn [acc _] (:game (generate-tribe acc))) 
      (create-game world) 
      (range n-tribes))) 

S объекты ince range знают, как разумно уменьшить себя, это превратится в цикл. Это reduce метод диапазона:

public Object reduce(IFn f, Object start) { 
    Object ret = f.invoke(start,n); 
    for(int x = n+1;x < end;x++) 
      ret = f.invoke(ret, x); 
    return ret; 
} 

Если состояние игры будет заводиться в атоме равно, то вы могли бы также рассмотреть dotimes обновить его.

(defn generate-game [world n-tribes] 
    (let [game (atom (create-game world))] 
    (dotimes [_ n-tribes] (swap! game (comp :game generate-tribe))) 
    game)) 

Iterate также является прекрасным решением. Больше обсуждений на Iteratively apply function to its result without generating a seq.

4

Если это та же функция повторяется n-tribes раз, а затем с помощью iterate и получение n-tribes -го элемента должно работать:

(defn generate-game [world n-tribes] 
    (let [ game (create-game world) 
     game (nth (iterate generate-tribe game) n-tribes)] 
     game)) 

Помните, что iterate создает ленивую последовательность так, ничего не будет вычисляться до тех пор, пока не поступит запрос.

Другой вариант применения comp к списку функций, в конце концов, это простая функция состав:

(generate-tribe (generate-tribe .... (generate-tribe game) ....)) 

           n-tribes times 

Так что-то вроде:

(defn generate-game [world n-tribes] 
    (let [ game (create-game world) 
     game ((apply comp (repeat n-tribes generate-tribe)) game)] 
     game)) 

выражает именно эту идею.

+1

лучше использовать' - >> 'in let' game (- >> (world-create-game) (...)) ' – edbond

+0

@edbond Исправьте меня, если я ошибаюсь, но макросы threading не будут работать, если количество функций для прокрутки неизвестно во время чтения. В тех случаях, когда это известно, это самое чистое решение. – soulcheck

+0

просто синтаксис сахара. Будет расширяться во время компиляции в тех же формах. – edbond

2

Не эксперт Clojure, но я ожидал бы

(defn generate-game [world n-tribes] 
    (nth (iterate generate-tribe (create-game world)) n-tribes)) 

или (менее лаконичным)

(defn generate-game [world n-tribes] 
    (let [game (create-game world)] 
    (nth (iterate generate-tribe game) n-tribes))) 

работать