The following code should work:
iex> x = 1
iex> fn(x, << y :: size(^x) >>) -> { x, y } end
The following code should not:
iex> x = 1
iex> fn(x, << y :: size(x) >>) -> { x, y } end
Both expressions should be valid outside fn match though.
I could take this.
I have one question: what is the different between << y :: size(^x) >> and << y :: size(x) >> outside fn match? Could you show me a example?
@mururu outside fn match, the first one uses the previous value of x and the second uses the current value (be it a previous value or a value from the current match).
However, we have to wait on this until they add variable matching for maps on R17, so there is no need to worry about it now. :)
Elixir can use a value from the current match as a size? IIRC, Erlang can't.
Both Elixir and Erlang can, unless you are in a function head.
And it will work as long as the value is defined before. Like << x, y :: size(x) >>.
And it will work as long as the value is defined before. Like << x, y :: size(x) >>.
Ah, that's right. Thanks. :)
Note to self: we need to add support back for ^ in comprehensions and function clauses too.
Any news on this? Just stumbled across ^ not being supported in function clauses.
EDIT: sorry, missed @josevalim's previous comment.
@hamiltop You don't need ^ in function clauses, use plain variables:
def f(x, x) do ...
It's in a closure.
iex(13)> x = 5
5
iex(14)> a = fn
...(14)> x -> x
...(14)> _ -> 0
...(14)> end
#Function<6.106461118/1 in :erl_eval.expr/5>
iex(15)> a.(2)
2
If I try to pin it:
iex(21)> a = fn
...(21)> ^x -> x
...(21)> _ -> 0
...(21)> end
** (CompileError) iex:22: unbound variable ^x
(stdlib) lists.erl:1352: :lists.mapfoldl/3
(elixir) src/elixir_fn.erl:26: :elixir_fn.translate_fn_match/2
(elixir) src/elixir_clauses.erl:26: :elixir_clauses.match/3
(elixir) src/elixir_clauses.erl:35: :elixir_clauses.clause/7
(elixir) src/elixir_fn.erl:9: anonymous fn/3 in :elixir_fn.translate/3
(stdlib) lists.erl:1352: :lists.mapfoldl/3
(elixir) src/elixir_fn.erl:14: :elixir_fn.translate/3
iex(21)>
Whereas, if I use a case inside one function clause:
iex(18)> a = fn(n) ->
...(18)> case n do
...(18)> ^x -> x
...(18)> _ -> 0
...(18)> end
...(18)> end
#Function<6.106461118/1 in :erl_eval.expr/5>
iex(19)> a.(2)
0
iex(20)> a.(5)
5
iex(21)>
Should I open a new issue for this?
@josevalim any thoughts on this?
@hamiltop that's what this issue is about, I have changed the title to make it clear. It will be added only after 1.0 though because I am waiting for variables in maps to ensure we get everything right.
Fixed in master.
:bow: Thank you! :+1:
I was just trying to use this to match a map key in a function head with another variable from the same match. Are the following examples revealing bugs, or am I just using this incorrectly?
x = fn(%{key => value}, key) -> value end
** (CompileError) iex:1: illegal use of variable key as map key inside match, maps can only match on existing variable by using ^key
defmodule Test do
def x(%{key => value}, key), do: value
end
** (CompileError) iex:1: illegal use of variable key as map key inside match, maps can only match on existing variable by using ^key
Usage of the pin operator, as suggested by the compile error, won't help either. It shouldn't be required for function heads anyway:
x = fn(%{^key => value}, key) -> value end
x.(%{a: 1}, :a)
** (CompileError) iex:1: unbound variable ^key
defmodule Test do
def x(%{^key => value}, key), do: value
end
** (CompileError) iex:1: unbound variable ^key
The error messages are correct. Maps only allow you to map on previously
defined variables, they can't come from the same pattern.
On Wednesday, January 27, 2016, Patrick Oscity [email protected]
wrote:
I was just trying to use this to match a map key in a function head with
another variable from the same match. Are the following examples revealing
bugs, or am I just using this wrong?x = fn(%{key => value}, key) -> value end
** (CompileError) iex:6: illegal use of variable key as map key inside match, maps can only match on existing variable by using ^key
(elixir) src/elixir_map.erl:157: anonymous fn/7 in :elixir_map.translate_map/4
(stdlib) lists.erl:1353: :lists.mapfoldl/3
(elixir) src/elixir_map.erl:156: :elixir_map.translate_map/4
(stdlib) lists.erl:1353: :lists.mapfoldl/3
(elixir) src/elixir_fn.erl:26: :elixir_fn.translate_fn_match/2defmodule Test do
def x(%{key => value}, key), do: value
end** (CompileError) iex:7: illegal use of variable key as map key inside match, maps can only match on existing variable by using ^key
(elixir) src/elixir_map.erl:157: anonymous fn/7 in :elixir_map.translate_map/4
(stdlib) lists.erl:1353: :lists.mapfoldl/3
(elixir) src/elixir_map.erl:156: :elixir_map.translate_map/4
(stdlib) lists.erl:1353: :lists.mapfoldl/3The pin operator won't help either, as suggested by the compile error. It
shouldn't be required for function heads anyway:x = fn(%{^key => value}, key) -> value end
x.(%{a: 1}, :a)** (FunctionClauseError) no function clause matching in :erl_eval."-inside-an-interpreted-fun-"/2
defmodule Test do
def x(%{^key => value}, key), do: value
end** (CompileError) iex:7: unbound variable ^key
(elixir) src/elixir_map.erl:157: anonymous fn/7 in :elixir_map.translate_map/4
(stdlib) lists.erl:1353: :lists.mapfoldl/3
(elixir) src/elixir_map.erl:156: :elixir_map.translate_map/4
(stdlib) lists.erl:1353: :lists.mapfoldl/3—
Reply to this email directly or view it on GitHub
https://github.com/elixir-lang/elixir/issues/2061#issuecomment-175480152
.
_José Valimwww.plataformatec.com.br
http://www.plataformatec.com.br/Founder and Director of R&D_
Alright, thanks for the info, too bad :( I guess this limitation comes from the BEAM? Is there anything we can do about it or would it be considered an "anti-feature" anyway?
I ran into this issue as well, hence finding this thread here. My question is, the variable binding is done sequentially, parameter by parameter correct? If so, if the order of the parameters were reverted it should work since key would be bound with the incoming parameter before the ^key was used in the map pattern-match expression yes?
defmodule Test do
def x(key, %{^key => value}), do: value
end
I expected it to work but it doesn't. Is it intended? In one hand, I think it is good that it is NOT supported since binding and then using a bound ^ parameter in same function header declaration might lead to more confusing code if abused. On the other hand, it will just force us to not bind the map
defmodule Test do
def x(key, m) do
case m do
%{^key => value} -> value
_ -> true
end
end
end
which is pretty much the same and works as expected.
iex(4)> Test.x(:a, %{})
true
iex(5)> Test.x(:a, %{:a => false})
false
I can see how supporting the pin operation in funcion head declaration for pattern matching might cause some problems, such as the need to delay the ^key binding until the other parameter that binds the key is performed and key is matched.
_(Still very new at Elixir but learning, sorry if I mentioned anything incorrect. And thanks for the great work on the language Jose!)_
No, pattern matching is not sequential. The whole pattern is analyzed at
once and not left to right. :)
It is also noting this is a VM limitation (and not an Elixir one!).
On Sunday, May 8, 2016, Daniel Parreira [email protected] wrote:
I ran into this issue as well, hence finding this thread here. My question
is, the variable binding is done sequentially, parameter by parameter
correct? If so, if the order of the parameters were reverted it should work
since key would be bound with the incoming parameter before the ^key was
used in the map pattern-match expression yes?defmodule Test do
def x(key, %{^key => value}), do: value
endI expected it to work but it doesn't. Is it intended? In one hand, I think
it is good that it is NOT supported since binding and then using a bound ^
parameter in same function header declaration might lead to more confusing
code if abused. On the other hand, it will just force us to not bind the mapdefmodule Test do
def x(key, m) do
case m do
%{^key => value} -> value
_ -> true
end
end
endwhich is pretty much the same and works as expected.
iex(4)> Test.x(:a, %{})
true
iex(5)> Test.x(:a, %{:a => false})
falseI can see how supporting the pin operation in funcion head declaration for
pattern matching might cause some problems, such as the need to delay the
_^key_ binding until the other parameter that binds the _key_ is
performed and _key_ is matched.
_
(Still very new at Elixir but learning, sorry if I mentioned anything
incorrect. And thanks for the great work on the language Jose!)_—
You are receiving this because you modified the open/close state.
Reply to this email directly or view it on GitHub
https://github.com/elixir-lang/elixir/issues/2061#issuecomment-217679553
_José Valimwww.plataformatec.com.br
http://www.plataformatec.com.br/Founder and Director of R&D_
:sadface
I'm wondering if it's a known limitation, that the first following example does not work, while the latter does:
Ecto.Multi.new
|> Ecto.Multi.run({:activity, index}, fn _ ->
Scheduling.create_activity(campaign, line_to_activity(line))
end)
|> Ecto.Multi.run({:timeslot, index}, fn %{{:activity, ^index} => activity} ->
Scheduling.create_timeslot(activity, line_to_activity(line))
end)
key = {:activity, index}
Ecto.Multi.new
|> Ecto.Multi.run(key, fn _ ->
Scheduling.create_activity(campaign, line_to_activity(line))
end)
|> Ecto.Multi.run({:timeslot, index}, fn %{^key => activity} ->
Scheduling.create_timeslot(activity, line_to_activity(line))
end)
Sorry to bump an old thread: I just got hit with same issue as @LostKobrakai.
Is it a known limitation? Maybe it is worth documenting in Kernel.SpecialForms/^?