【问题标题】:Open modules in Elixir?在 Elixir 中打开模块?
【发布时间】:2015-02-03 05:18:30
【问题描述】:

Ruby 有开放类,非常方便(尽管被一些人斥责),并且 Elixir 从 Ruby 中大量借鉴,所以我希望 Elixir 允许我在关闭模块后重新打开模块并添加宏,但这确实不能以我尝试的方式工作。有没有办法做到这一点? Elixir 中是否提供此功能?

为了具体说明,让我们以 Chris McCord 的 Metaprogramming Elixir 为例:

defmodule Math do
  defmacro say({:+, _, [lhs, rhs]}) do 
    quote do
      lhs = unquote(lhs)
      rhs = unquote(rhs)
      result = lhs + rhs
      IO.puts "#{lhs} plus #{rhs} is #{result}"
      result
    end
  end

  defmacro say({:*, _, [lhs, rhs]}) do 
    quote do
      lhs = unquote(lhs)
      rhs = unquote(rhs)
      result = lhs * rhs
      IO.puts "#{lhs} times #{rhs} is #{result}" 
      result
    end 
  end
end

如果我再添加一个减法宏

defmodule Math do
  defmacro say({:-, _, [lhs, rhs]}) do
    quote do
      lhs    = unquote(lhs)
      rhs    = unquote(rhs)
      result = lhs - rhs
      IO.puts "#{lhs} minus #{rhs} is #{result}"
      result
    end
  end
end

我收到一条警告,提示我正在重新定义模块 Math,并且最初定义的宏失败。所以很明显我的方法不是正确的,但是还有另一种方法可以实现同样的目标吗?

【问题讨论】:

  • 您不应将类的概念与模块混淆。虽然它们有一些相似之处,但它们远非同一件事。例如,Elixir 模块中没有私有数据之类的东西。
  • 顺便说一下,您的示例并没有真正使用宏功能。建议您尽可能坚持使用功能,这可以在这里轻松完成。只需使用def 而不是defmacro 并删除所有quotes 和unquotes。
  • 是的,没错,但我希望您意识到这不是 my 的示例,而是 Chris McCord 的示例,它只是用于演示目的的“琐碎”示例。不过你的观点是正确的。

标签: elixir


【解决方案1】:

您无法重新打开模块。由于 Elixir 是一种编译语言,因此从源代码到可执行表示的方式是单向的。更改代码的机制(例如宏)在编译期间进行评估。但是,Elixir 允许您进行热代码交换,即。 e.您可以在运行时替换已编译的模块。

我认为这有一些有趣的含义。您可以在运行时更改程序——实际上,您可以控制源代码,因此您可以在不更改其他部分的情况下更换模块的各个部分。尽管如此,我还是喜欢将所有东西都放在一个地方的想法。在 Elixir 中,当您查看一个模块时,您就知道自己拥有什么*。

所以如果这个问题只是关于一个方便的开发工作流程——你最接近 Ruby 向类添加方法的能力是将你的模块保存在一个文件中,并在你去的时候从 iex 重新编译它。


* 严格来说,您可能仅通过查看模块就知道正在运行什么代码。当您使用协议时,您还需要查看所有协议实现,它们可能分散在您的代码库中,或者更糟糕的是,它们可能分布在多个应用程序中。

【讨论】:

  • 既然你提到了协议,值得补充的是,人们会在 Ruby 中进行猴子补丁以添加扩展的地方可以通过协议完全解决。 defprotocol 的文档提到了例如一个空白协议。可以在这里找到更深入的比较:blog.plataformatec.com.br/2014/06/…
  • 我了解协议,但我看不到如何将其应用于原始问题中的问题。它仍然不允许您将命名函数添加到方法中,还是我弄错了?
  • Patrick,您不能扩展现有模块,但协议是一种扩展机制,因为它允许任何开发人员对任何数据类型实现预定义的行为。我同意,尽管这是一条细线,并且鉴于问题中的示例,您的答案更完整!
  • 虽然如果协议可以基于整个模式进行调度,而不仅仅是类型,那就太好了。例如,这将允许我们为不同的结构编写不同的实现。你有没有考虑过这样的功能?
猜你喜欢
  • 1970-01-01
  • 2011-08-07
  • 1970-01-01
  • 1970-01-01
  • 2018-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-24
相关资源
最近更新 更多