Erlang多态性:同一合约的多个实现?

cetgtptt  于 2022-12-08  发布在  Erlang
关注(0)|答案(5)|浏览(122)

正确的Erlang方法是什么?如何在它们之间切换?

oyt4ldly

oyt4ldly1#

虽然其他人提到了 * behavior * 特性,但它只是一个小的帮助,用于确保实现回调结构的模块中的所有函数。如果您有两个实现,ab,并且都实现了相同的函数,您可以静态地用a替换调用模块中的b。对于有更好实现的静态配置,这是优选的。
如果问题是动态性质的,你可以

Mod = a,
 Mod:f(Args).

然后在代码集Mod中进行适当的调用,这样可以在程序运行时动态地控制要调用哪个模块,但并不完全清楚您需要哪一个。

5jvtdoz2

5jvtdoz22#

多态性的一个很好的例子是qlc模块和结构table。请参阅etsdetsmnesia等中的各种M:table/1,2实现。例如在shell中尝试ets:table(ets:new(foo, [set])).,并查看qlc文档和示例。

ttvkxqim

ttvkxqim3#

由于Erlang是动态类型的,函数保护(when … ->位)是表达多态性的方式。
例如:

len (T) when is_tuple(T) -> size(T);
len (L) when is_list(L) -> length(L).
uurity8g

uurity8g4#

也许可以看看行为概念。至少对我来说,在接口定义和多个实现模块方面与OOP有一点相似之处。

qhhrdooz

qhhrdooz5#

If I realized your question, here is example for approach, that pretty much works for me. This approach helps to separate interface and implementation.
"Interface" module.

-module(contract).

-export([
    new/2,
    do_something/2
]).

%% Behavioural callbacks definition. Each of "derived" modules should implement it.
-callback new(Arg :: any()) -> {ok, ImplState :: any()} | {error, Reason :: atom()}.
-callback do_something( Arg :: any(), ImplState :: any() ) -> {ok, ReturnVal :: any(), NewImplState :: any()} | {error, Reason :: atom()}.

%% Opaque state to hold implementation details
-record(
    contract_impl, {
        impl_module :: module(),
        impl_state  :: any()
    }
).

%% Interface for creation "polymorphic" instance, like base-class constructor.
new(ImplModule, ImplInitArgs) ->
  case ImplModule:new(ImplInitArgs) of
    {ok, State} ->
      {ok,
        #contract_impl {
          impl_module = ImplModule,
          impl_state = State
        }
      };
    {error, Reason} ->
      {error, Reason}
  end.

%% Interface function, like an abstract method in OOP.
do_something(
  Arg,
  #contract_impl {
    impl_module = ImplModule,
    impl_state = ImplState
  } = ContractImpl
) ->
  case ImplModule:do_something(Arg, ImplState) of
    {ok, ReturnVal, NewState} ->
      {ok, ReturnVal, ContractImpl#contract_impl{ impl_state = NewState }};
    {error, Reason} -> {error, Reason}
  end.

Some implementation example (like derived class).

-module(foo).

-behaviour(contract).

-export([
  new/1,
  do_something/2
]).

-record(
  foo_state, {
    repeat_count
  }
).

new(Options) ->
  {ok,
    #foo_state{
      repeat_count = proplists:get_value(repeat_count, Options)
    }
  }.

do_something(Arg, #foo_state{ repeat_count = RepeatCount } = State) ->
  Result = [ io_lib:format("Foo ~p", [Arg]) || _Index <- lists:seq(1, RepeatCount) ],
  {ok, Result, State}.

Now you can do the following:

usage_example() ->
  {ok, State} = contract:new(foo, [{repeat_count, 15}]),
  {ok, Result, NewState} = contract:do_something("bar", State),
  ok.

I hope this helps.

相关问题