Массивы и петли в Clojure - PullRequest
0 голосов
/ 03 мая 2018

Я пытаюсь выучить язык программирования Clojure. Мне трудно понять это, хотя. Я хотел бы попытаться реализовать что-то настолько простое, как это (например):

int[] array = new int[10];
array[0] =1; 
int n = 10; 

for(int i = 0; i <= n; i++){
    array[i] = 0; 
}
return array[n]; 

Поскольку я новичок в Clojure, я даже не понимаю, как это реализовать. Было бы очень полезно, если бы кто-то мог объяснить или привести аналогичный пример того, как работают массивы / циклы в Clojure. Я пытался провести какое-то исследование, но что касается моего понимания, у Clojure действительно нет циклов for.

Ответы [ 4 ]

0 голосов
/ 03 мая 2018

Clojure способ написания цикла Java for, который вы написали, заключается в том, чтобы в первую очередь подумать, почему вы делаете цикл. Существует много вариантов переноса цикла Java в Clojure. Выбор среди них зависит от вашей цели.

Способы сделать десять нулей

Как сообщает Carcigenicate, если вам нужно десять нулей в коллекции, рассмотрите:

(repeat 10 0)

Возвращает последовательность ( lazy one), что обычно в Clojure для работы с последовательными значениями. Если вместо этого десять индексов должны быть доступны по индексу, поместите их в вектор с:

(vec (repeat 10 0))

или

(into [] (repeat 10 0))

Или вы можете просто написать векторный литерал прямо в своем коде:

[0 0 0 0 0 0 0 0 0 0]

И если вам по какой-то причине вам нужен массив Java , то вы можете сделать это с помощью to-array:

(to-array (repeat 10 0))

Но помните совет от справочной документации Clojure по взаимодействию с Java :

Clojure поддерживает создание, чтение и модификацию массивов Java [но] рекомендуется ограничить использование массивов для взаимодействия с библиотеками Java, которые требуют их в качестве аргументов, или использовать их в качестве возвращаемых значений.

В этих документах перечислены некоторые функции для работы с массивами Java, в первую очередь, когда они необходимы для взаимодействия Java или «для поддержки мутаций или операций с более высокой производительностью». Почти во всех случаях Clojurists просто использовать вектор.

Цикл в Clojure

Что делать, если вы делаете что-то кроме десяти нулей? Способ Clojure «зацикливаться» зависит от того, что вам нужно.

Вам может понадобиться рекурсия, для которой у Clojure есть loop / recur:

(loop [x 10]
  (when-not (= x 0)
    (recur (- x 2))

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

(for [x coll])
  (calculate-y x))

Вам может потребоваться выполнить итерацию по нескольким коллекциям, подобно вложенным циклам в Java:

(for [x ['a 'b 'c] 
      y [1 2 3]]
  (foo x y))

Если вам просто нужно произвести побочный эффект несколько раз, несколько раз - это ваше варенье:

(repeatedly 10 some-fn)

Если вам нужно создать побочный эффект для каждого значения в коллекции, попробуйте дозыq :

(doseq [x coll]
  (do-some-side-effect! x))

Если вам нужно создать побочный эффект для целого ряда, вы можете использовать doseq, например так:

(doseq [x (range 10)] 
  (do-something! x))

... но dotimes похоже на doseq со встроенным диапазоном :

(dotimes [x 9] 
  (do-something! x))

Еще более распространенными, чем эти циклические конструкции, являются функции Clojure, которые создают значение для каждого элемента в коллекции, например, map и его родственников, или которые перебирают коллекции либо для специальных целей (например, filter и * 1083). *) или для создания какого-либо нового значения или коллекции (например, reduce).

0 голосов
/ 03 мая 2018

Хорошее начало можно получить здесь:

0 голосов
/ 03 мая 2018

Я думаю, что последняя точка в ответе @ Ли должна быть сильно подчеркнута.

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

; Create 10 0s, then put them in a vector
(vec (repeat 10 0))

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

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

0 голосов
/ 03 мая 2018

Вы можете создавать и изменять массивы в clojure, ваш пример будет выглядеть так:

(defn example []
  (let [arr (int-array 10)
        n 10]
    (aset arr 0 1)
    (doseq [i (range (inc n))]
      (aset arr i 0))
    (aget arr n)))

Имейте в виду, что в этом примере будет сгенерировано исключение, поскольку array[i] выходит за границы, когда i = 10.

Обычно вы будете использовать векторы вместо массивов, поскольку они неизменны.

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