Это плохая практика, чтобы пытаться отслеживать итерации при использовании Reduce / Map в Clojure? - PullRequest
3 голосов
/ 06 ноября 2019

Так что, будучи новичком в Clojure и в целом в функциональном программировании, я иногда (цитирую книгу) «чувствую, что ваш любимый инструмент у вас забрали». Пытаясь лучше понять эту вещь, я занимаюсь проблемами манипулирования строками.

Итак, зная, что функциональная парадигма - это все о рекурсии (и других вещах), я использовал хвостовые рекурсивные функции для выполнения своих задач. Обычно я делаю с циклами, затем пытаюсь реализовать, используя карту или уменьшить. Для тех, кто более опытен, это звучит как нормальное занятие?

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

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

Вот мой пример:

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

(defn new-string-from-five
  "This function takes a character at position char-at from each of the strings to make a new vector"
  [five-strings char-at]
  (reduce (fn [result string]
            (conj result (get-char-at string char-at)))
    []
    five-strings))

Старый : «abc», «def», «ghi» »jkl "" mno "-> [adgjm] (всегда берется из индекса 0)


Изменено :" abc "" def "" ghi "" jkl "" mno "-> [aeijn] (indexувеличивается и возвращается назад)

Ответы [ 2 ]

3 голосов
/ 06 ноября 2019

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

По вашему вопросу, вероятно, наиболее распространенная вещь, которую нужно сделать, - добавить индекс в исходную коллекцию. (в данном случае строка) с использованием map-indexed

(user=> (map-indexed vector [9 9 9])
([0 9] [1 9] [2 9])

Итак, для вашего примера

(defn new-string-from-five
  "This function takes a character at position char-at from each of the strings to make a new vector"
  [five-strings char-at]
  (reduce (fn [result [string-idx string]]
            (conj result (get-char-at string (+ string-idx char-at))))
    []
    (map-indexed vector five-strings)))

Но как бы я построил карту с индексированием? Ну

Не лениво:

(defn map-indexed' [f coll]
  (loop [idx 0
         res []
         rest-coll coll]
    (if (empty? rest-coll)
      res
      (recur (inc idx) (conj res (f idx (first rest-coll))) (rest rest-coll)))))

Лениво (рекомендую пока не пытаться это понять):

(defn map-indexed' [f coll]
  (letfn [(map-indexed'' [idx f coll]
            (if (empty? coll)
              '()
              (lazy-seq (conj (map-indexed'' (inc idx) f (rest coll)) (f idx (first coll))))))]
    (map-indexed'' 0 f coll)))
1 голос
/ 06 ноября 2019

Вы можете использовать reductions:

(defn new-string-from-five
  [five-strings]
  (->> five-strings
       (reductions
        (fn [[res i] string]
          [(get-char-at string i) (inc i)])
        [nil 0])
       rest
       (mapv first)))

Но в этом случае, я думаю, map, mapv или map-indexed чище. Например,

(map-indexed 
  (fn [i s] (get-char-at s i))
  ["abc" "def" "ghi" "jkl" "mno"])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...