Dict.merge(totals, counts, &(&2 + &3))
capture &2 cannot be defined without &1
Dict.merge(totals, counts, fn(_k, v1, v2) -> v1 + v2 end)
clojure.core/merge-with([f & maps])Returns a map that consists of the rest of the maps conj-ed ontothe first. If a key occurs in more than one map, the mapping(s)from the latter (left-to-right) will be combined with the mapping inthe result by calling (f val-in-result val-in-latter).
The reasoning is that there is no way to create an ampersand function with unused last arguments, example: fn x, y, _ -> x * y end, so there should be no way to create an ampersand function with unused arguments at all, for consistency.
Why we don't allow the shorter version is because we generally don't overload functions based on the arity of the given function in Elixir. That could be discussed though.
--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
I just tried to merge two string -> int dictionaries, where I wanted to add the integers together whenever the same key appeared in both dictionaries. Here's what I tried first:Dict.merge(totals, counts, &(&2 + &3))This gives me the error:capture &2 cannot be defined without &1
We have &Enum.map/2 which expands to fn arg1, arg2 -> Enum.map(arg1, arg2) end. So if we allowed &(...) with no arguments &Enum.map/2 would become ambiguous. Is it the previous expansion or (fn -> Enum.map end) / 2
To ask a related question, why is "&(...)" as a substitute for "fn -> ... end" (no arguments) disallowed?
--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
Incidentally, I find the following contortion interesting (in that it isn’t an error):
iex(6)> &(Enum.map) / 2
&Enum.map/2
This is the very reason that we have an ambiguity. The parenthesis are optional for &, it is just an ordinary operator that happens to be a macro that expands to an anonymous function. & is not parsed as a function call. Let’s look at the AST for the expressions:
iex(1)> quote do: &Enum.map/2
{:&, [],
[{:/, [],
[{{:., [], [{:__aliases__, [], [:Enum]}, :map]}, [], []}, 2]}]}
iex(2)> quote do: &(Enum.map)/2
{:&, [],
[{:/, [],
[{{:., [], [{:__aliases__, [], [:Enum]}, :map]}, [], []}, 2]}]}
As you can see they are parsed the same way regardless of the parenthesis. Just like how 2+(2) is parsed to the same AST as 2+2.
The fact that we can capture functions of arity 0 has nothing to do with it, it is not a technical limitation. We chose to disallow it because the expressions would be ambiguous or confusing at best.
--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
I think the mistake here is that you are seeing & as a syntax construct. Elixir has very few syntax constructs, & is in fact just an operator that follows all the general syntactic rules of Elixir, the only thing special about it would be its place in the precedence table (*). We cannot make special rules for & regarding parsing, that means no special whitespace handling or special handling of parenthesis.
In many other languages most things like if, def and defmodule are special keywords in the language, because of this they can make up special syntax rules for those keywords. In Elixir they are all macros and parsed just like all other function calls, i.e. no special rules.
Lets look at your proposals and why they might not work in a language such as Elixir.
&func/arity -> capture a function
Agree, this is how it works today.
&(expression) -> generate an anonymous function taking 0 to n arguments (&1..&n)
(func/arity) is an expression. Ambiguous?
&(func/arity) -> generate an anonymous function of arity 0, which returns func/arity
We can’t special handle parenthesis. (((expr))) should be parsed as expr and so (func/arity) should be parsed as func/arity.
&(func)/number -> syntax error (functions can’t be divided)
We should not add a syntax error here. For example someone creating a DSL may want to use this syntax, so why add this restriction?
func/arity -> an individual token, the function with specified arity
func / 2 -> calls func, divides the result by 2.
Lets not add special whitespace handing of the division operator. How do we determine (at compile time) that func is actually a function?
&func -> syntax error, no arity specified
Remember, no special parenthesis handling :). &(func) should parse as &func.
& &1 -> syntax error, &1 is not a function, no arity specified.
Again the parenthesis. & &1 should parse the same as & (&1) and &(&1).
I guess the trouble I’m having is that Enum.map/2 seems like one token to me, but (Enum.map)/2 seems like 3, and given the way that parses, & &1+3 should be equivalent to &(&1+3), but it isn’t. I presume this is a precedence issue.
AFAIK, I could very well be wrong, there is no way to construct such a precedence table.
As you see it is very hard to make the syntax work for perfectly for each use case while still keeping the language’s syntax rules general. The footnote below shows an example where it seems we were unable to keep it 100% general.
(*) Actually, this is not entirely true. There is some special handling to make & 1 / 2 parse as (&1) / 2, and & foo / 2 parse as &(foo/2). This, I agree, is a slight wart in the language. Should we have a different operator for binding a named function (&foo/2) and creating an anonymous function (&(&1 + &2))?
--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
(*) Actually, this is not entirely true. There is some special handling to make
& 1 / 2parse as(&1) / 2, and& foo / 2parse as&(foo/2). This, I agree, is a slight wart in the language. Should we have a different operator for binding a named function (&foo/2) and creating an anonymous function (&(&1 + &2))?
To clarify the changes to & in the coming release. & is being changed to have a lower precedency, lower than all other operators except ->. We are keeping the special handling of &1, because all unary operators followed by a number binds strongly (+1, -1 and &1).
& &1 + 2 will parse as &((&1) + 2).
--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
somefunc asdf |> someotherfunc gherg Which i think should turn into
somefunc(asdf) |> someotherfunc(gherg), but I think it actually turns into
somefunc(asdf |> someotherfunc(gherg)) or possibly
somefunc(asdf |> someotherfunc) gherg
All binary operators work like this with the exception of ->. Without this behaviour we wouldn’t be able to have macros like assert. assert can inspect the given expression and with the knowledge from this give very good error messages. With your suggestion assert foo == bar would parse as (assert(foo)) == bar and make assert unable to see the ==.
Because of this it is recommended to always use parenthesis when piping. You should really always use parenthesis except for the cases where you know for sure there can be no ambiguity.
def func, do:
needsParens(sadf)def func do
doesn’tNeedParens sadf
end
None of them need parenthesis, def func, do: needsParens sadf is perfectly valid syntax. If you would call needsParens with multiple arguments on the other hand, then you would need parenthesis. For example: def func, do: needsParens arg1, arg2. Since def is macro (not a keyword) and we are just calling the macro we cannot know if the last comma belongs to the def call or the needsParens call. Again, use your parenthesis :).
I think I understand intellectually why this is the case.I was confused for a long time about why one version needs a comma before the do, and the other one doesn’t. And I’m still not sure I completely understand. Is do/end its own macro, or are there two different versions of def? (If do/end is a macro, does it insert a comma in front of whatever it turns into?) And why doesn’t one need a comma after do:? (I don’t have a problem with this syntax, but it was confusing when I was first trying to learn the language). It makes it look like its doing special parsing, even if it isn’t; which in turn makes it confusing when & can’t do special parsing.
do ... end are not macros, they are keywords in the language used to enclose a block. A block is a list expressions that will be evaluated in order and return the last expression.
def foo() do
a
b
end
The code above is parsed like this: def(foo(), [do: __block__([a, b])]). __block__ is not a function, it is actually not even a macro, when the compiler sees __block__ it will emit code that evaluates all expressions in the given list and returns the last one. And as you can see do ... end becomes [do: ...]. [] is optional around keyword lists so you can also write it as do: .... Now you can see that the two ways to define functions really are the same.
def is just a macro where the first argument is the function head and second argument is the function body.
--
You received this message because you are subscribed to the Google Groups "elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-ta...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
somefunc asdf |> someotherfunc gherg
Another isdef func, do:needsParens(sadf)def func dodoesn'tNeedParens sadfend
def func dodoesn'tNeedParens sadfend
def func, do: (doesn'tNeedParens sadf)
some func, needParens sadf, ola
some func, needParens(sadf, ola)
some func, needParens(sadf), ola
if some, do: needParens sadf, ola, else: bar
And I'm not sure why arity has to be indicated with what looks like a division (other than adoption from erlang), if its going to be the cause of some strange stuff.
&hello/0
&unquote(fun)/unquote(arity)
&unquote(fun_arity)
And as you can see
do ... endbecomes[do: ...]