Reputation: 12402
I've noticed something surprising with Elixir's for
comprehensions when used to pipe the results into a function.
For example, these forms work:
foo = fn(list) ->
for n <- list do
n + 1
end
|> Enum.reverse
end
foo.([1,2,3])
# [4, 3, 2]
foo = fn(list) ->
for(n <- list, do: (n + 1))
|> Enum.reverse
end
foo.([1,2,3])
# [4, 3, 2]
But this doesn't, as it considers the |> Mod.func
on the second line part of the do
block of the macro:
foo = fn(list) ->
for n <- list, do: n + 1
|> Enum.reverse
end
foo.([1,2,3])
** (Protocol.UndefinedError) protocol Enumerable not implemented for 2
(elixir) lib/enum.ex:1: Enumerable.impl_for!/1
(elixir) lib/enum.ex:116: Enumerable.reduce/3
(elixir) lib/enum.ex:1636: Enum.reduce/3
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6
(stdlib) erl_eval.erl:228: :erl_eval.expr/5
(elixir) lib/enum.ex:1623: Enum."-reduce/3-lists^foldl/2-0-"/3
I would guess that is has to do with how macros are expanded and their value returned, but interestingly these work:
bar = fn(list) ->
if true, do: list
|> Enum.reverse
end
bar.([1,2,3])
# [3, 2, 1]
bar = fn(list) ->
if true, do: Enum.map(list, &(&1 + 1))
|> Enum.reverse
end
bar.([1,2,3])
# [4, 3, 2]
Upvotes: 1
Views: 1299
Reputation: 2813
I think it's because of:
warning: you are piping into a function call without parentheses, which may be ambiguous. Please wrap the function you are piping into in parentheses.
This works:
iex()> foo = fn(list) ->
...()> (for n <- list, do: n + 1)
...()> |> Enum.reverse
...()> end
#Function<6.52032458/1 in :erl_eval.expr/5>
iex()> foo.([1,2,3])
[4, 3, 2]
without parentheses your function like:
foo = fn(list) ->
for n <- list, do: n + 1 |> Enum.reverse
end
and n + 1
isn't a list
so (Protocol.UndefinedError) protocol Enumerable not implemented for 2
Upvotes: 4