我知道我有点像Ruby-ish甚至是Java-ish,但我经常会遇到这种情况。
我想定义一些通用模块(可以使用元编程),它将使用一些将在" children"中指定的变量/函数。模块(可能use
这个通用模块。)
我想它就像:
defmodule Parent do
defmacro __using__(_) do
quote do
def function do
__MODULE__.other_function
end
end
end
end
以及后来:
defmodule Child do
use Parent
def other_function do
# some real work
end
end
我经常需要"抽象"一些函数,最好的是通过定义一些模块变量@var
可以访问" parent"模块,但我知道它并没有像这样工作。
有没有办法调用将在&#34中定义的函数;包括"模块?
答案 0 :(得分:3)
我认为你正走在正确的轨道上。如果你添加@callback
来为"抽象"定义spec
功能会更好。我将用一个工作实例来解释:
defmodule Fibonacci do
@callback fib(number :: integer) :: integer
defmacro __using__(_) do
quote do
@behaviour Fibonacci
def fibonacci(n) when not is_integer(n), do: {:error, "Not integer"}
def fibonacci(n) when n < 0, do: {:error, "Negative number"}
def fibonacci(n), do: {:ok, __MODULE__.fib(n)}
def fibonacci!(n) do
case fibonacci(n) do
{:error, reason} -> raise reason
{:ok, n} -> n
end
end
end
end
end
使用Fibonacci
的每个模块都需要实现回调函数fib/1
。此外,use
Fibonacci
模块的每个模块都将具有处理错误的函数fibonacci/1
和引发错误的fibonacci!/1
。
所以,让我们直接递归实现fib/1
:
defmodule Direct do
use Fibonacci
def fib(0), do: 0
def fib(1), do: 1
def fib(n), do: fib(n - 1) + fib(n - 2)
end
对于尾递归:
defmodule Tail do
use Fibonacci
def fib(0), do: 0
def fib(1), do: 1
def fib(n), do: fib(1, 1, n - 2)
defp fib(_, value, 0), do: value
defp fib(n_2, n_1, n), do: fib(n_1, n_2 + n_1, n - 1)
end
所以在iex
我们可以调用不同的实现:
iex(1)> Direct.fibonacci(10)
{:ok, 55}
iex(2)> Tail.fibonacci!(10)
55
iex(3)> Tail.fibonacci!(-10)
** (RuntimeError) Negative number
另外,如果您忘记在模块中定义fib/1
函数,那么编译器会向您发出警告:
defmodule Warning do
use Fibonacci
end
* warning: undefined behaviour function fib/1 (for behaviour Fibonacci)
如果您想使用此代码,请点击此链接 http://elixirplayground.com?gist=606fe8c283443f03c7af08f85c888fe3
我希望这能回答你的问题。
答案 1 :(得分:2)
根据您的确切用例,可能有多种方法可以执行此操作。最简单的方法就是使用更高阶的函数而不使用任何元编程。
defmodule Parent do
def function(function_passed_as_variable) do
function_passed_as_variable.()
end
end
defmodule Child do
def function do
Parent.function(&other_function/1)
end
def other_function do
#some real function
end
end
我保留了名称Parent
和Child
来引用您的代码,但在这种情况下它不适合。
要实现多态性(一个函数根据数据执行不同的操作),您可以使用模式匹配:
def function({:first_type, data}), do: data*2
def function({:second_type, data}), do: data+2
def function(data), do: data
还可以为不同的结构和其他数据类型定义协议。
选择正确的模式可能并不容易,所以请随意评论更具体的例子。