Как связать функции, чтобы оценить их позже - PullRequest
0 голосов
/ 03 января 2019

Я учу Clojure использовать его с Quil для создания творческого искусства, и я хотел бы попытаться понять немного больше о функции let и макросе читателя, вероятно.

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

У меня сейчас есть этот кусок кода:

(let [dabs (take 10 (repeatedly #(make-watercolor 
                                   (mkpt 
                                     (randomNormal 0.1 0.9) 
                                     (randomNormal 0.1 0.9))
                                   (w (randomNormal 0.4 0.7)))))]
    (draw-multiple-watercolor dabs 3))

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

Мой вопрос: есть ли способ сделать что-то подобное

(let [randCoord (randomNormal 0.1 0.9) ;This..
      randPoint (mkpt randCoord randCoord) ;..and this doesn't should be evaluated here, but on the repeatedly function calls
      dabs (take 10 (repeatedly #(make-watercolor 
                                   randPoint ;Evaluation here
                                   (w (randomNormal 0.4 0.7)))))]
    (draw-multiple-watercolor dabs 3))

1 Ответ

0 голосов
/ 03 января 2019

Один из вариантов - использовать тот же подход, который вы использовали с функцией, которую вы передаете repeatedly: просто оберните выражения в функции, которые не принимают аргументов (или только те аргументы, которые вы хотите изменить), тогда они будутоценивать каждый раз, когда вы вызываете функцию.

(let [rand-coord (fn [] (randomNormal 0.1 0.9)) ;; or #(randomNormal 0.1 0.9)
      make-dab #(make-watercolor (mkpt (rand-coord) (rand-coord))
                                 (w (randomNormal 0.4 0.7)))
      dabs (take 10 (repeatedly make-dab))]
  (draw-multiple-watercolor dabs 3))

Также обратите внимание на letfn для определения функций в области не верхнего уровня / пространства имен.

Вы также можете найти Threading макросы, такие как ->, ->>, as->, some->, cond-> и т. Д., Могут сделать некоторый код более читабельным.Например, если вы изменили draw-multiple-watercolor, чтобы взять его последовательность мазков last (что является довольно распространенной практикой для функций, работающих с последовательностями в Clojure), то вы можете сделать что-то вроде этого:

(let [rand-coord (fn [] (randomNormal 0.1 0.9)) ;; or #(randomNormal 0.1 0.9)
      make-dab #(make-watercolor (mkpt (rand-coord) (rand-coord))
                                 (w (randomNormal 0.4 0.7)))]
  (->> make-dab
       (repeatedly 10) ;; note: repeatedly can take a # of iterations
       (draw-multiple-watercolor 3)))
...