2012-04-26 2 views
7

Я просто написал этот код:Как лучше перебрать государства в Clojure (монады?)

(defn parameters [transform-factory state] 
    (lazy-seq (let [[r1 state] (uniform state) 
        [r2 state] (uniform state) 
        [t state] (transform-factory state)] 
       (cons [t [r1 r2]] (parameters transform-factory state))))) 

(defn repeated-transform [mosaic n transform-factory state] 
    (reduce transform-square mosaic 
    (take n (parameters transform-factory state)))) 

функция parameters генерирует ленивую последовательность значений, полученных из state, которые используются параметризировать повторное преобразование что-то («мозаика» в этом случае).

Мне кажется, что parameters показывает довольно распространенный шаблон, который возникает, когда у вас есть state, который должен быть перенесен (в данном случае для генерации случайных значений). есть ли название для этого?

есть ли лучший способ написать первую функцию? связанные проблемы могут часто решаться с помощью reduce, который «переносит» состояние, но здесь мне нечего уменьшать. Аналогично, reductions, похоже, не подходит. это хороший пример для монады? (из теоретического pov я не вижу, как вы определяете способ объединения нескольких экземпляров в один, но, возможно, это не меняет практическое приложение - похоже, что такие проблемы монады решаются в другом месте, где какое-то государство нуждается в быть перенесенным).

(ps упомянутые случайные числа, но я не могу заменить это решением, которое использует изменчивое состояние за кулисами - как «обычные» случайные подпрограммы - по причинам, не связанным с вопросом).

+0

> (ps упомянутые случайные числа, но я не могу заменить это решением, которое использует изменчивое состояние за кулисами - как «обычные» случайные подпрограммы - по причинам, не связанным с вопросом). Вы можете использовать a) псевдослучайный генератор, несущий семя вокруг, или b) скопируйте изменчивое состояние (чтобы его не изменяли). Я использовал этот подход для реализации [pure mersenne twister] [1]. [1]: http://hackage.haskell.org/package/mersenne-random-pure64-0.2.0.3 –

+0

Я пришел сюда, чтобы задать тот же вопрос – jes5199

+0

@DonStewart - я не понимаю, как это будет измените то, что я прошу. на самом деле то, что я делаю, это копирование состояния - вот что «государство» выше, и источник моих проблем. –

ответ

4

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

Общие рекомендации по использованию монады являются:

  • Последовательного выполнения (операции трубопровода)
  • многоразовой модульной сторона обработки эффекта (например: обработка ошибок/регистрация/ состояния)
  • Держите бизнес-логику в чистоте в чистых функциях

Некоторые ресурсы на монах, которые я нашел очень полезными (для Clojure), являются

Адам Smyczek: Введение в монады (Видео) http://www.youtube.com/watch?v=ObR3qi4Guys

и Джим Duey: Монады в Clojure http://www.clojure.net/2012/02/02/Monads-in-Clojure/

+0

спасибо - я посмотрю. надеялся, что это была известная проблема, но, видимо, нет, так что есть «лучший ответ» cookie: o) –

3

[ответить на себя, так как это лучшее решение я нашел до сих пор ]

вы можете переписать выше как складку по функциям. поэтому функции становятся данными, состояние является «пройденным», а используемая функция применяет каждую функцию по очереди к состоянию и накапливает результат.

Я не вижу элегантный способ реализовать это - функция, которая складывается, кажется, «новая», и вам нужен дополнительный шаблон для добавления/разделения состояния и аккумулятора - поэтому я завернул весь процесс в функцию fold-over. source is here и an example of the function in use is here.

+0

это чувствует себя рядом со мной. Похоже, возможно, что этот подход с некоторыми макросами может превратиться в складчатое 'let', и, возможно, это будет полезно. – jes5199

+0

да, следующий мне нужно узнать о макросах в clojure ... –

3

Что-то, что вы должны проверить, это -> и ->>, макросы для потоковой передачи.

Вместо кода, как это:

(let [state (dosomething state) 
     state (dosomethingelse state) 
     state (dolastthing state)] 
    state) 

Вы можете написать:

(-> state (dosomething) (dosomethingelse) (dolasttthing)) 

, который "нити" состояние с помощью функций, в конечном итоге вернуть его.

Теперь ваш код точно не соответствует тому, что я написал. То, как я предполагаю, может следовать за ним, было, если ваши функции взяли и вернули hashmaps. то есть (равномерное состояние) может вернуться {:state state-val :r1 r1-val}.

Тогда вы могли бы переписать код так:

(->> {:state state} (merge uniform) (merge uniform) (transform-factory)) 

Гораздо приятнее! :)

+0

oooh. благодаря! посмотрим на это. звучит хорошо. –

Смежные вопросы