J'essaye d'écrire une fonction de module simple qui prend une expression comme une chaîne comme "123 + 45"
et renvoie une réponse. Alors:Elixir: opérateur d'infixe dynamique
Calculator.calculate("123 + 45")
# => 168
Je pensais à diviser simplement la chaîne sur (" ")
pour obtenir les entiers et l'opérateur, puis en appelant essentiellement Code.eval_string
sur elle. Il y avait là ma première tentative naïve:
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
Puis, en exécutant, je reçois cette erreur:
** (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
Je ne pouvais pas comprendre pourquoi c
était en cours d'évaluation en fonction. Je soupçonne que cela a à voir avec la variable operator
dans la fonction anonyme. J'ai confirmé qu'en le réécrivant avec un opérateur codé en dur:
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
En effet, ceci produit le résultat attendu. La question est:
Pourquoi la présence de la liaison de variable operator
dans la fonction anonyme a-t-elle entraîné l'évaluation de c
en tant que fonction?
Il ressort de la documentation sur Code.eval_string
fait apparaître comme si les fixations variables peuvent être à peu près tout aussi longtemps qu'ils sont trouvés dans la liste de mots clés est le deuxième argument eval_string
. Dans ma deuxième tentative, j'ai pensé à essayer de convertir l'opérateur de la chaîne d'entrée dans un atome et de convertir l'opérateur d'un infixe à un appel de fonction (par exemple, de 1 + 3
à quelque chose comme 1.(:+, [3])
.) Mais cela ne fonctionne pas. . semblent être une syntaxe valide
ma deuxième question est:
est-il possible d'écrire une expression avec un opérateur infixe tel que +
en fonction, et de pouvoir ne définir dynamiquement opérateur un atome?