【发布时间】:2017-10-09 23:51:09
【问题描述】:
我正在尝试编写一个简单的模块函数,它将表达式作为"123 + 45" 之类的字符串并返回一个答案。所以:
Calculator.calculate("123 + 45")
# => 168
我想只在(" ") 上拆分字符串以获取整数和运算符,然后基本上调用Code.eval_string 就可以了。这是我第一次天真的尝试:
defmodule Calculator do
def calculate(str) do
[x, oper, y] = String.split(str, " ")
formula = "a = fn (c, d) -> c operator d end; a.(c, d)"
{answer, _ } = Code.eval_string(formula, [
c: String.to_integer(x),
operator: String.to_atom(oper),
d: String.to_integer(y)
])
answer
end
end
然后,在运行它时,我收到此错误:
** (CompileError) nofile:1: undefined function c/1
(elixir) src/elixir_fn.erl:10: anonymous fn/3 in :elixir_fn.expand/3
(stdlib) lists.erl:1239: :lists.map/2
(elixir) src/elixir_fn.erl:14: :elixir_fn.expand/3
我不明白为什么 c 被评估为一个函数。我怀疑它与匿名函数中的operator 变量有关。我通过用硬编码运算符重写它确认了这一点:
defmodule Calculator do
def calculate(str) do
[x, _, y] = String.split(str, " ")
formula = "a = fn (c, d) -> c + d end; a.(c, d)"
{answer, _ } = Code.eval_string(formula, [
c: String.to_integer(x),
d: String.to_integer(y)
])
answer
end
end
确实,这会产生预期的结果。问题是:
为什么匿名函数中存在operator 变量绑定导致c 被评估为函数?
从Code.eval_string 上的文档看来,变量绑定似乎可以是任何东西,只要它们在作为eval_string 的第二个参数的关键字列表中找到。
在我的第二次尝试中,我考虑尝试将运算符从输入字符串转换为原子,并将运算符从中缀转换为函数调用(即,从 1 + 3 转换为 1.(:+, [3]) 之类的东西。但那似乎不是有效的语法。
所以我的第二个问题是:
是否可以用+ 之类的中缀运算符作为函数编写表达式,然后将该运算符动态定义为原子?
【问题讨论】:
标签: elixir