1

我想((IStringer)object).ToString()用 Erlang 写类似(在 C# 中)的东西。经过一些研究,我了解到 Elixir 有一个叫做 Protocols 的东西,它与 C# 非常相似(以由内而外的方式)。然后我在 Erlang 中提出了这个想法/代码——这对我来说已经足够好了:

?stringer(my_val):to_string().

它要么返回预期值,要么返回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

编码:

-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()]).

输出是:

"[1,2]"
"cute_atom"
not_implemented

我在 Windows 8 64 位上的 Erlang R16 B2 (V5.10.3) 32 位上执行此操作。

4

1 回答 1

6

您看到的警告是 Erlang 错误。如果 Erlang 看到您在字面元组中调用函数,它会显示警告。我在使用 Elixir 时看到了这一点,我在 Elixir 的编译器中将其静音,但忘记将其作为错误报告给 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.

并直接调用该函数。您的实现只是简单地使用 Erlang 在一天结束时提供的经典的临时多态性。这种方法的局限性在于,由于 dispatch 被硬编码为 ?stringer,扩展to_string/1行为以使用新数据类型的唯一方法是重新实现和替换整个stringer模块。

下面是一个可以帮助您思考的问题示例:如果应用程序 A 定义了一个名为 的“协议” stringer,那么应用程序 B 和 C 如何将此协议扩展为它们自己的数据类型,并且都被应用程序 D 使用而不会丢失功能?

简而言之,Elixir 中协议的工作方式是让 stringer 模块成为中间调度模块。所以 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).

并想象代码被包裹在检查模块是否存在的东西上,如果不存在则相应地失败。当然,所有这些都是通过简单地定义协议自动为您定义的。还有一种机制(称为整合)可以将协议编译为发布时的快速调度机制。

于 2013-12-13T08:19:45.293 回答