Ответ 1
Это хороший вызов, чтобы иметь и решать его, безусловно, даст вам некоторое представление о функциональном программировании.
Решение таких задач в функциональных языках обычно reduce
(часто называемое fold
). Я начну с короткого ответа (а не прямого перевода), но не стесняйтесь просить о последующих действиях.
Приведенный ниже подход обычно не работает в языках функционального программирования:
map = %{}
Enum.each [1, 2, 3], fn x ->
Map.put(map, x, x)
end
map
Карта в конце будет по-прежнему пуста, потому что мы не можем мутировать структуры данных. Каждый раз, когда вы вызываете Map.put(map, x, x)
, он возвращает новую карту. Поэтому нам нужно явно получить новую карту после каждого перечисления.
Мы можем достичь этого в Elixir, используя сокращение:
map = Enum.reduce [1, 2, 3], %{}, fn x, acc ->
Map.put(acc, x, x)
end
Уменьшение будет выдавать результат предыдущей функции в качестве аккумулятора для следующего элемента. После выполнения кода выше, переменная map
будет %{1 => 1, 2 => 2, 3 => 3}
.
По этим причинам мы редко используем each
при перечислении. Вместо этого мы используем функции в модуле Enum
, которые поддерживают широкий диапазон операций, в конце концов возвращаясь к reduce
, когда нет другой опции.
EDIT: чтобы ответить на вопросы и перейти к более прямому переводу кода, это то, что вы можете сделать, чтобы проверить и обновить карту по ходу:
Enum.reduce blogs, %{}, fn blog, history ->
posts = get_posts(blog)
Enum.reduce posts, history, fn post, history ->
if Map.has_key?(history, post.url) do
# Return the history unchanged
history
else
do_thing(post)
Map.put(history, post.url, true)
end
end
end
Фактически, набор будет лучше здесь, поэтому дайте возможность реорганизовать это и использовать набор в этом процессе:
def traverse_blogs(blogs) do
Enum.reduce blogs, HashSet.new, &traverse_blog/2
end
def traverse_blog(blog, history) do
Enum.reduce get_posts(blog), history, &traverse_post/2
end
def traverse_post(post, history) do
if post.url in history do
# Return the history unchanged
history
else
do_thing(post)
HashSet.put(history, post.url)
end
end