Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
547 views
in Technique[技术] by (71.8m points)

functional programming - Specify arity using only or except when importing function on Elixir

I'm studying Elixir and when I use only or except operators when importing functions from a module I need to specify an arity number. Why?

e.g.

import :math, only: [sqrt: 1]

or

import :math, except: [sin: 1, cos: 1]
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Across the Erlang ecosystem functions are identified by name + arity. In most other languages you can overload functions by name. In other words, in the Erlang world foo/1 (that is, foo(one_arg)) is a completely different function than foo/2 (as in, foo(one_arg, two_arg)), but in Python or Ruby "foo" is the complete function identity and it can be invoked with a flexible number of arguments.

The convention is to name functions that mean the same thing the same name, especially in the case of recursively defined iterative functions like:

factorial(N) -> factorial(1, N).

factorial(A, 0) -> A;
factorial(A, N) -> factorial(A * N, N - 1).

Notice there are two periods, meaning there are two completely independent definitions here. We could just as well write:

fac(N) -> sum(1, N).

sum(A, 0) -> A;
sum(A, N) -> sum(A * N, N - 1).

But you will notice that the second version's savings in terms of character strokes is drastically outweighed by the convolution of its semantics -- the second version's internal function name is an outright lie!

The convention is to name related functions the same thing, but in actuality overloading functions by arity is not allowed in the Erlang ecosystem. To make such overloading acceptable would require significant feature additions to the compiler of a language that compiles to Erlang's bytecode, and that would be a pointless waste of painful effort. The current situation is about as good as we can get in a dynamically typed functional language (without it becoming a statically typed functional language... and that's another discussion entirely).

The end result is that you have to specify exactly what function you want to import, whether in Erlang or Elixir, and that means identifying it by name + arity. Recognizing that the common convention is to use the same name for functions that do the same thing but have different argument counts (often simply writing a cascade of curried definitions to enclose common defaults), Elixir provides a shortcut to including functions by groups instead of enumerating them.

So when you import :math, only: [sqrt: 1] you only take math:sqrt/1 and left the rest of the module out (were there a math:sqrt/2 you would have ignored it). When you import :math, except: [sin: 1, cos: 1] you take everything but math:sin/1 and math:cos/1 (were there a math:sin/2 you would have taken it). The name + arity is a distinct identity. Imagine a big KV store of available functions. The keys are {module, func, arity}, meaning they are an atomic value to the system. If you're familiar with Erlang even a little this may strike you as familiar, because you deal with the tuple {Module, Function, Args} all the time.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...