1defmodule Function do
2  @moduledoc """
3  A set of functions for working with functions.
4
5  Anonymous functions are typically created by using `fn`:
6
7      iex> add = fn a, b -> a + b end
8      iex> add.(1, 2)
9      3
10
11  Anonymous functions can also have multiple clauses. All clauses
12  should expect the same number of arguments:
13
14      iex> negate = fn
15      ...>   true -> false
16      ...>   false -> true
17      ...> end
18      iex> negate.(false)
19      true
20
21  ## The capture operator
22
23  It is also possible to capture public module functions and pass them
24  around as if they were anonymous functions by using the capture
25  operator `Kernel.SpecialForms.&/1`:
26
27      iex> add = &Kernel.+/2
28      iex> add.(1, 2)
29      3
30
31      iex> length = &String.length/1
32      iex> length.("hello")
33      5
34
35  To capture a definition within the current module, you can skip the
36  module prefix, such as `&my_fun/2`. In those cases, the captured
37  function can be public (`def`) or private (`defp`).
38
39  The capture operator can also be used to create anonymous functions
40  that expect at least one argument:
41
42      iex> add = &(&1 + &2)
43      iex> add.(1, 2)
44      3
45
46  In such cases, using the capture operator is no different than using `fn`.
47
48  ## Internal and external functions
49
50  We say that functions that point to definitions residing in modules, such
51  as `&String.length/1`, are **external** functions. All other functions are
52  **local** and they are always bound to the file or module that defined them.
53
54  Besides the functions in this module to work with functions, `Kernel` also
55  has an `apply/2` function that invokes a function with a dynamic number of
56  arguments, as well as `is_function/1` and `is_function/2`, to check
57  respectively if a given value is a function or a function of a given arity.
58  """
59
60  @type information ::
61          :arity
62          | :env
63          | :index
64          | :module
65          | :name
66          | :new_index
67          | :new_uniq
68          | :pid
69          | :type
70          | :uniq
71
72  @doc """
73  Captures the given function.
74
75  Inlined by the compiler.
76
77  ## Examples
78
79      iex> Function.capture(String, :length, 1)
80      &String.length/1
81
82  """
83  @doc since: "1.7.0"
84  @spec capture(module, atom, arity) :: fun
85  def capture(module, function_name, arity) do
86    :erlang.make_fun(module, function_name, arity)
87  end
88
89  @doc """
90  Returns a keyword list with information about a function.
91
92  The returned keys (with the corresponding possible values) for
93  all types of functions (local and external) are the following:
94
95    * `:type` - `:local` (for anonymous functions) or `:external` (for
96      named functions).
97
98    * `:module` - an atom which is the module where the function is defined when
99    anonymous or the module which the function refers to when it's a named function.
100
101    * `:arity` - (integer) the number of arguments the function is to be called with.
102
103    * `:name` - (atom) the name of the function.
104
105    * `:env` - a list of the environment or free variables. For named
106      functions, the returned list is always empty.
107
108  When `fun` is an anonymous function (that is, the type is `:local`), the following
109  additional keys are returned:
110
111    * `:pid` - PID of the process that originally created the function.
112
113    * `:index` - (integer) an index into the module function table.
114
115    * `:new_index` - (integer) an index into the module function table.
116
117    * `:new_uniq` - (binary) a unique value for this function. It's
118      calculated from the compiled code for the entire module.
119
120    * `:uniq` - (integer) a unique value for this function. This integer is
121      calculated from the compiled code for the entire module.
122
123  **Note**: this function must be used only for debugging purposes.
124
125  Inlined by the compiler.
126
127  ## Examples
128
129      iex> fun = fn x -> x end
130      iex> info = Function.info(fun)
131      iex> Keyword.get(info, :arity)
132      1
133      iex> Keyword.get(info, :type)
134      :local
135
136      iex> fun = &String.length/1
137      iex> info = Function.info(fun)
138      iex> Keyword.get(info, :type)
139      :external
140      iex> Keyword.get(info, :name)
141      :length
142
143  """
144  @doc since: "1.7.0"
145  @spec info(fun) :: [{information, term}]
146  def info(fun), do: :erlang.fun_info(fun)
147
148  @doc """
149  Returns a specific information about the function.
150
151  The returned information is a two-element tuple in the shape of
152  `{info, value}`.
153
154  For any function, the information asked for can be any of the atoms
155  `:module`, `:name`, `:arity`, `:env`, or `:type`.
156
157  For anonymous functions, there is also information about any of the
158  atoms `:index`, `:new_index`, `:new_uniq`, `:uniq`, and `:pid`.
159  For a named function, the value of any of these items is always the
160  atom `:undefined`.
161
162  For more information on each of the possible returned values, see
163  `info/1`.
164
165  Inlined by the compiler.
166
167  ## Examples
168
169      iex> f = fn x -> x end
170      iex> Function.info(f, :arity)
171      {:arity, 1}
172      iex> Function.info(f, :type)
173      {:type, :local}
174
175      iex> fun = &String.length/1
176      iex> Function.info(fun, :name)
177      {:name, :length}
178      iex> Function.info(fun, :pid)
179      {:pid, :undefined}
180
181  """
182  @doc since: "1.7.0"
183  @spec info(fun, item) :: {item, term} when item: information
184  def info(fun, item), do: :erlang.fun_info(fun, item)
185
186  @doc """
187  Returns its input `value`. This function can be passed as an anonymous function
188  to transformation functions.
189
190  ## Examples
191
192      iex> Function.identity("Hello world!")
193      "Hello world!"
194
195      iex> 'abcdaabccc' |> Enum.sort() |> Enum.chunk_by(&Function.identity/1)
196      ['aaa', 'bb', 'cccc', 'd']
197
198      iex> Enum.group_by('abracadabra', &Function.identity/1)
199      %{97 => 'aaaaa', 98 => 'bb', 99 => 'c', 100 => 'd', 114 => 'rr'}
200
201      iex> Enum.map([1, 2, 3, 4], &Function.identity/1)
202      [1, 2, 3, 4]
203
204  """
205  @doc since: "1.10.0"
206  @spec identity(value) :: value when value: var
207  def identity(value), do: value
208end
209