在Elixir中打开模块? [英] Open modules in Elixir?

查看:91
本文介绍了在Elixir中打开模块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Ruby具有开放式类,非常方便(尽管有些人re病了),并且Elixir大量借鉴了Ruby,因此我希望Elixir允许我在关闭模块后重新打开模块并向其添加宏,但这确实做到了不能以我尝试的方式工作。有什么办法可以做到这一点?此功能在Elixir中是否可用?



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

  defmodule Math do 
defmacro say({:+,_,[lhs,rhs]})做
quote do
lhs = unquote( lhs)
rhs = unquote(rhs)
结果= lhs + rhs
IO.puts#{lhs}加#{rhs}是#{result}
结果
end
end

defmacro say({:*,_,[lhs,rhs]})做
quote do
lhs = unquote(lhs)
rhs = unquote(rhs)
结果= lhs * rhs
IO.puts#{lhs}乘以#{rhs}是#{结果}
结果
结束
结束
结束

如果我再添加一个用于减法的宏

  defmodule数学做
defmacro say({:-,_,[lhs,rhs]})做
quote do
lhs = unquote(lhs)
rhs = unquote(rhs)
结果= lhs-rhs
IO.puts #{lhs}减去#{rhs}是#{result}
结果
结束
结束
结束

我收到警告,我正在重新定义模块Math,最初定义的宏失败。因此,显然我的方法不合适,但是有另一种方法可以实现相同的目标吗?

解决方案

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



我认为这具有一些有趣的含义。您可以在运行时更改程序–在实践中,您可以控制源代码,因此可以交换模块的各个部分而无需更改其他部分。不过,我还是喜欢将所有内容都放在一个地方的想法。在Elixir中,当您查看一个模块时,您会确切地知道您所拥有的*。 Ruby能够向类添加方法的功能是将模块保存到文件中,并在运行时从iex重新编译。






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


Ruby has open classes, which are very handy (though reviled by some), and Elixir borrows heavily from Ruby, so I expected Elixir to allow me to reopen a module and add macros to it after having closed it, but this did not work in the way I tried it. Is there some way to do this? Is this feature available yet in Elixir?

To make this concrete, let's take an example from Chris McCord's 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

If I then add a macro for subtraction

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

I get a warning that I'm redefining module Math, and the initially defined macros fail. So obviously my approach is not the right one, but is there another approach that can accomplish the same goal?

解决方案

You cannot re-open a module. Since Elixir is a compiled language, the way from source code to an executable representation is one-way. The mechanisms that alter code, such as macros, are evaluated during compilation time. However, Elixir allows you to do hot code swapping, i. e. you can replace a compiled module during runtime.

I think this has some interesting implications. You get the ability to change the program at runtime – in practice, you control the source code and so you can swap out individual parts of a module without changing others. Still, I like the idea of having everything in one place. In Elixir, when you look at a module you know exactly what you've got*.

So if this question is only about a convenient development workflow – the closest you will come to Ruby's ability to add methods to a class is to save your module in a file and re-compile it from iex as you go.


* Strictly speaking, you might not know exactly what code is running by just looking at a module. When you are using protocols, you kind of need to look at all of the protocol implementations as well, which may be scattered throughout your codebase, or, even worse, they may be distributed across multiple applications.

这篇关于在Elixir中打开模块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆