4 ms·
> Why not allow function literals that define multiple arity implementations? Something like... Perhaps I was unable to get my point across but that's what the
by josevalim 3y ago
> Why not allow function literals that define multiple arity implementations? Something like...
Perhaps I was unable to get my point across but that's what the blog post is meant to answer. The TL;DR is two fold:
1. In order for the feature to be worthwhile, we should remove the distinction between name-arity pairs altogether from the language (so module functions and variables effectively exist in a single namespace)
2. However, this double namespace is a core feature of the Erlang VM, so it would require radical changes to it (or you would need a statically typed language with FFI bindings to Erlang in order to "work-around" this efficiently)
Overall Elixir is a Lisp-2 language, with two distinct namespaces, and it requires conversion between functions of those namespaces. It does not have currying, it does not support point-free style, but in practice guards and pipelines help alleviate those concerns.
Regarding your gist, I am honestly not sure if 15 minutes is enough to evaluate a programming language, but in case you want to dig deeper, many questions are answered in the official guides. Here are some quick links:
* On maps vs keywords: https://elixir-lang.org/getting-started/keywords-and-maps.html https://elixir-lang.org/getting-started/keywords-and-maps.ht...
* On do-blocks and syntax: https://elixir-lang.org/getting-started/optional-syntax.html https://elixir-lang.org/getting-started/optional-syntax.html
- jakear 3y agoRight, I wasn't putting that it forward as a sign of my deep investment in the topic. More just a laugh at dumb things I got worked up over in college. thanks for the links. That all said, I don't see why you'd need to remove the double namespace feature in order to have function literals that define multiple interpretations. The value namespace still has just the single value-land binding to the literal, only the `call` procedure (the .( operator, so to speak) needs to be modified to dispatch to the appropriate function-land name as determined by airity and the literal the value was bound to.
- josevalim 3y agoI see. :D I am lucky my time in college was just before the internet "became permanent". Double lucky that all pictures and recordings from my cover band disappeared with it! Anyway, regarding the dot, we could make `fun.(...)` dispatch to the correct arity, but that would make every function dispatch slower. However, even if we assume that's an ok price to pay, it wouldn't take long for people to request function capture without an arity, such as `&Foo.bar` (otherwise it would feel incomplete). And this feature would add further penalties as we further postpone the call. Both would also reduce the amount of compile-time checks we can emit and hurt integration with the overall Erlang ecosystem. On the large scale of trade-offs, I don't think it is worth it. :)
- throwawaymaths 3y agoI think the real question we all want to know is why lambdas don't have "do"
- sodapopcan 3y agoLambad definitions don't take arguments, they jump straight to argument matching. Take: case value do true -> "true" false -> "false" _ -> "uh..." end vs fn true -> "true" false -> "false" _ -> "uh..." end `do` is simply syntactic sugar for a keyword list argument containing a `:do` key: if(true, [{:do, "hi there"}]) So it wouldn't make sense for `fn` to take a `do`.
- throwawaymaths 3y agofn do true -> "true" false -> "false" _ -> "uh..." end
- sodapopcan 3y agoAs much as I despise people responding in pure code, you're right, it's technically `fn/1` [0]. Even though the docs say `fn(clauses)`, `cond/1`, which requires the `do`, also says `cond(clauses)` [1] so looks like I'm wrong. [0] https://hexdocs.pm/elixir/1.14/Kernel.SpecialForms.html#fn/1 https://hexdocs.pm/elixir/1.14/Kernel.SpecialForms.html#fn/1 [1] https://hexdocs.pm/elixir/1.14/Kernel.SpecialForms.html#cond/1 https://hexdocs.pm/elixir/1.14/Kernel.SpecialForms.html#cond...
- josevalim 3y agoBecause `do` binds the farthest away. In these examples: case some_fun(1) do end case some_fun() do end case some_fun do end We all know `do` binds to case. Therefore, if `fn` used `do`, the `do` would bind to the farthest call to: # this code Enum.map list, fn do end # or this code map list, fn do end would both bind `do` to `map`. Of course we could special case `fn do` but having `do` bind to different places based on `fn` would be extremely confusing.