使用理解力模板化函数
Templatizing function using comprehension
假设我们有以下实现:
defmodule SomeModule do
@celcius_coefficient 800
@rheinan_coefficient 900
@fahrenheit_coefficient 1000
@available_units [:celcius, :rheinan, :fahrenheit]
def foo(some_struct) do
some_var = get_var(some_struct, :var_name)
if some_var == :kelvin do
initialize(some_struct)
else
bar(some_struct, some_var)
end
end
defp bar(struct, :celcius) do
mult(struct, @celcius_coefficient)
end
defp bar(struct, :rheinan) do
mult(struct, @rheinan_coefficient)
end
defp bar(struct, :fahrenheit) do
mult(struct, @fahrenheit_coefficient)
end
end
有以*_coefficient
开头的模块属性,其中*
是表示某物的关键字。我们正在实施 bar/2
来匹配所有可用的子句。实现比较繁琐,当我们需要添加一个新的单元时,我们需要实现一个新的函数来匹配新的单元,这个函数要通过相同的表达式求值。
An implementation in Comeonin library 使用推导式为所有子句生成函数。我建议采用以下方法:
defmodule SomeModule do
@celcius_coefficient 800
@rheinan_coefficient 900
@fahrenheit_coefficient 1000
@available_units [:celcius, :rheinan, :fahrenheit]
def foo(some_struct) do
some_var = get_var(some_struct, :var_name)
if some_var == :kelvin do
initialize(some_struct)
else
bar(some_struct, some_var)
end
end
for unit <- @available_units do
defp bar(struct, unquote(unit)) do
coefficient = unquote(Module.get_attribute(__MODULE__, :"#{Atom.to_string(unquote(unit))}_coefficient"))
mult(struct, coefficient)
end
end
end
模块属性应在编译时使用 Module.get_attribute/2
检索,因为它在运行时不可用。
我们还需要取消对 unit
参数的引用,以便为函数提供正确的原子。
它抛出一个编译错误,说:unquote called outside quote
。
尝试在某些地方放置 quote
子句,但没有任何帮助。
我想我对 Elixir 中的元编程有一些误解和困惑。
你有什么建议吗?
我也在纠结用defp
还是defmacrop
来定义bar/2
。做这种事情的正确构造是什么?
谢谢。
您不需要在内部 unit
值周围取消引号,因为它已经被取消引用了:
coefficient = unquote(
Module.get_attribute(__MODULE__, :"#{Atom.to_string(unit)}_coefficient")
)
节目:
defmodule SomeModule do
@celcius_coefficient 800
@rheinan_coefficient 900
@fahrenheit_coefficient 1000
@available_units [:celcius, :rheinan, :fahrenheit]
for unit <- @available_units do
def bar(struct, unquote(unit)) do
coefficient = unquote(Module.get_attribute(__MODULE__, :"#{Atom.to_string(unit)}_coefficient"))
{struct, coefficient}
end
end
end
IO.inspect SomeModule.bar(1, :celcius)
IO.inspect SomeModule.bar(2, :fahrenheit)
输出:
{1, 800}
{2, 1000}
(我把函数public做了测试,如果不想在本模块外使用可以再设为private)
I'm also in a dilemma about using defp or defmacrop to define bar/2. What would be the correct construct for doing such kind of thing?
只在需要将函数作为宏使用时才定义宏。在这种情况下,您不需要那个,所以 defp
(或 def
)就可以了。
假设我们有以下实现:
defmodule SomeModule do
@celcius_coefficient 800
@rheinan_coefficient 900
@fahrenheit_coefficient 1000
@available_units [:celcius, :rheinan, :fahrenheit]
def foo(some_struct) do
some_var = get_var(some_struct, :var_name)
if some_var == :kelvin do
initialize(some_struct)
else
bar(some_struct, some_var)
end
end
defp bar(struct, :celcius) do
mult(struct, @celcius_coefficient)
end
defp bar(struct, :rheinan) do
mult(struct, @rheinan_coefficient)
end
defp bar(struct, :fahrenheit) do
mult(struct, @fahrenheit_coefficient)
end
end
有以*_coefficient
开头的模块属性,其中*
是表示某物的关键字。我们正在实施 bar/2
来匹配所有可用的子句。实现比较繁琐,当我们需要添加一个新的单元时,我们需要实现一个新的函数来匹配新的单元,这个函数要通过相同的表达式求值。
An implementation in Comeonin library 使用推导式为所有子句生成函数。我建议采用以下方法:
defmodule SomeModule do
@celcius_coefficient 800
@rheinan_coefficient 900
@fahrenheit_coefficient 1000
@available_units [:celcius, :rheinan, :fahrenheit]
def foo(some_struct) do
some_var = get_var(some_struct, :var_name)
if some_var == :kelvin do
initialize(some_struct)
else
bar(some_struct, some_var)
end
end
for unit <- @available_units do
defp bar(struct, unquote(unit)) do
coefficient = unquote(Module.get_attribute(__MODULE__, :"#{Atom.to_string(unquote(unit))}_coefficient"))
mult(struct, coefficient)
end
end
end
模块属性应在编译时使用 Module.get_attribute/2
检索,因为它在运行时不可用。
我们还需要取消对 unit
参数的引用,以便为函数提供正确的原子。
它抛出一个编译错误,说:unquote called outside quote
。
尝试在某些地方放置 quote
子句,但没有任何帮助。
我想我对 Elixir 中的元编程有一些误解和困惑。
你有什么建议吗?
我也在纠结用defp
还是defmacrop
来定义bar/2
。做这种事情的正确构造是什么?
谢谢。
您不需要在内部 unit
值周围取消引号,因为它已经被取消引用了:
coefficient = unquote(
Module.get_attribute(__MODULE__, :"#{Atom.to_string(unit)}_coefficient")
)
节目:
defmodule SomeModule do
@celcius_coefficient 800
@rheinan_coefficient 900
@fahrenheit_coefficient 1000
@available_units [:celcius, :rheinan, :fahrenheit]
for unit <- @available_units do
def bar(struct, unquote(unit)) do
coefficient = unquote(Module.get_attribute(__MODULE__, :"#{Atom.to_string(unit)}_coefficient"))
{struct, coefficient}
end
end
end
IO.inspect SomeModule.bar(1, :celcius)
IO.inspect SomeModule.bar(2, :fahrenheit)
输出:
{1, 800}
{2, 1000}
(我把函数public做了测试,如果不想在本模块外使用可以再设为private)
I'm also in a dilemma about using defp or defmacrop to define bar/2. What would be the correct construct for doing such kind of thing?
只在需要将函数作为宏使用时才定义宏。在这种情况下,您不需要那个,所以 defp
(或 def
)就可以了。