Kav*_*ian 1 erlang protocols interface elixir
我想((IStringer)object).ToString()在Erlang中写一些(在C#中).经过一番研究后,我了解到Elixir有一种称为Protocols的东西,它几乎与C#相同(以内向外的方式).然后我在Erlang中提出了这个想法/代码 - 这对我来说非常好:
?stringer(my_val):to_string().
Run Code Online (Sandbox Code Playgroud)
它要么返回预期值,要么返回not_implemented原子!
但有2个问题:
1 - 为什么没有人在Erlang中使用这个或基于有状态模块来推广事物?(OTP除了和一些Erlangers谈话,他们不知道实际上OTP是围绕着这个建立的!所以真的需要改变Erlang的教学和推广方式.我可能会感到困惑.)
2 - 为什么我收到这个警告?那个电话实际上永远不会失败.
警告:
stringer.erl:18: Warning: invalid module and/or function name; this call will always fail
stringer.erl:19: Warning: invalid module and/or function name; this call will always fail
stringer.erl:20: Warning: invalid module and/or function name; this call will always fail
Run Code Online (Sandbox Code Playgroud)
代码:
-module(stringer).
-export([to_string/1,sample/0]).
-define(stringer(V), {stringer, V}).
to_string({stringer, V}) when is_list(V) ->
to_string(V, nop);
to_string({stringer, V}) when is_atom(V) ->
to_string(V, nop);
to_string({stringer, _V}) ->
not_implemented.
to_string(V, _Nop) ->
Buffer = io_lib:format("~p",[V]),
lists:flatten(Buffer).
sample() ->
io:format("~p~n", [?stringer([1,2]):to_string()]),
io:format("~p~n", [?stringer(cute_atom):to_string()]),
io:format("~p~n", [?stringer(13):to_string()]).
Run Code Online (Sandbox Code Playgroud)
输出是:
"[1,2]"
"cute_atom"
not_implemented
Run Code Online (Sandbox Code Playgroud)
我在Windows 8 64位上的Erlang R16 B2(V5.10.3)32位上执行此操作.
您看到的警告是Erlang错误.如果Erlang看到你在一个文字元组中调用一个函数,它会显示警告.我在使用Elixir时已经看过这个,我在Elixir的编译器中对它进行了沉默,但忘记将它作为bug报告给Erlang团队.抱歉.
大多数开发人员在Erlang中实际上避免了有状态模块的事情.添加它们是为了支持一个名为"参数化模块"的功能,该功能随后被删除,但底层的调度机制仍然存在.如果您搜索Erlang Questions邮件列表,您可以找到关于该主题的大量讨论.请注意,Elixir中的协议并没有像那样实现.
实际上,与普通函数相比,您的实现似乎似乎没有添加任何内容.例如,您可以简单地写:
to_string(V) when is_list(V); is_atom(V) ->
Buffer = io_lib:format("~p",[V]),
lists:flatten(Buffer);
to_string(V) ->
not_implemented.
Run Code Online (Sandbox Code Playgroud)
并直接调用该函数.您的实现只是使用Erlang在一天结束时提供的经典ad-hoc多态.这种方法的局限性在于,由于调度被硬编码为?stringer,因此扩展to_string/1行为以使用新数据类型的唯一方法是重新实现并替换整个stringer模块.
下面是一个可以帮助您思考这个问题的示例:如果应用程序A定义了一个名为"协议"的stringer应用程序,那么应用程序B和C如何将此协议扩展到它们自己的数据类型,并且应用程序D都可以使用它们而不会丢失功能?
简单来说,协议在Elixir中的工作方式是使纵梁模块成为中间调度模块.因此stringer模块实际上是这样工作的:
to_string(V) when is_list(V) ->
string_list:to_string(V);
to_string(A) when is_atom(A) ->
string_atom:to_string(A);
%% ...
to_string(A) when is_tuple(A) ->
string_tuple:to_string(A).
Run Code Online (Sandbox Code Playgroud)
并且假设代码被包裹在检查模块是否存在的东西周围,如果不存在则相应地失败.当然,所有这些都是通过简单定义协议自动定义的.还有一种机制(称为合并)可以将协议编译为版本上的快速调度机制.
| 归档时间: |
|
| 查看次数: |
574 次 |
| 最近记录: |