Оценка выражения в Lua в среде

Этот вопрос имеет некоторую отсылку к вопросу Оценка выражения в Lua в математической среде Следующий код работает.

tbl = {}
tbl.sin = math.sin
tbl.cos = math.cos

function mathEval(exp)
  return load("return " .. exp, exp, "t", tbl)()
end

print(mathEval("sin(0)"))
print(mathEval("sin(0)+cos(1)+2^2"))

Однако следующий код не работает.

tbl = {}
tbl.sin = math.sin
tbl.cos = math.cos

function mathEval(exp)
  return load("return " .. tostring(exp), tostring(exp), "t", tbl)()
end

print(mathEval(sin(0)))
print(mathEval(sin(0)+cos(1)+2^2))

Я хочу оценивать выражения без использования кавычек. Как это сделать?

Надо было уточнить перед ответом, но зачем такие ограничения? Можете ли вы оценить выражение напрямую, например. r = sin(0)+cos(1)+2^2? Можете ли вы изменить выражение для доступа к вашей таблице (tbl.sin(0)+tbl.cos(1)+2^2)?

Luke100000 11.01.2023 12:55
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
50
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы передаете sin(0) и sin(0)+cos(1)+2^2 функции mathEval(exp), но поскольку sin и cos не являются глобальными переменными и математическая библиотека не передается как среда, Lua не может их найти.

Если вы хотите использовать математические функции с функцией mathEval, вы можете использовать таблицу tbl, созданную ранее, для вызова математических функций, например:

print(mathEval("tbl.sin(0)"))
print(mathEval("tbl.sin(0)+tbl.cos(1)+2^2"))

или, в качестве альтернативы, вы можете передать математическую библиотеку или математические функции в качестве повышающего значения функции load():

function mathEval(exp)
  return load("return " .. tostring(exp), tostring(exp), "t", _ENV)()
end

print(mathEval("math.sin(0)"))
print(mathEval("math.sin(0)+math.cos(1)+2^2"))

Это можно сделать без кавычек, это должно работать:

expression = string.format("%s(%d)", "math.sin", 0)
fn = load( "return " .. expression)
result = fn()
print(result) -- Output: 0

В этом примере функция string.format() используется для создания строки "math.sin(0)". Результирующая строка затем передается функции load(), как и раньше. Таким образом, вам не нужно использовать кавычки в строке, и вы можете использовать заполнители для объединения переменных.

Я предполагаю, что вы не хотите оценивать выражение перед передачей результата в качестве аргумента? Затем вы можете обернуть свое выражение в функцию, которая затем лениво вызывается. Он заменяет среду на tbl, выполняет функцию и возвращает среду.

tbl = {}
tbl.sin = math.sin
tbl.cos = math.cos

function mathEval(func)
    local old = _ENV
    _ENV = tbl
    local r = func()
    _ENV = old
    return r
end

print(mathEval(function() return sin(0)+cos(1)+2^2 end))

Примечание. Это работает, потому что mathEval и функция используют одно и то же значение _ENV upvalue, поэтому изменение его для mathEval также меняет его для анонимной функции. Это означает, что может произойти сбой, если mathEval находится в другом фрагменте, используя другое значение _ENV upvalue, чем анонимная функция, переданная mathEval, например. когда это требуется: require("mathEval"); print(mathEval(function() return sin(42) end))

LMD 11.01.2023 12:56
Ответ принят как подходящий

Проблема со строкой print(mathEval(sin(0)+cos(1)+2^2)) заключается в том, что аргумент mathEval оценивается до запуска mathEval, поэтому вычисление переменных sin и cos нельзя отложить до среды mathEval; то есть mathEval получает значение, а выражение вообще не вычисляется!

Прежде всего, одним из вариантов оценки таких математических выражений без использования mathEval будет просто временное изменение вашей среды:

local prev_env = _ENV -- this is needed to restore the environment later on
_ENV = tbl -- enter custom environment
local result = sin(0)+cos(1)+2^2
_ENV = prev_env -- restore environment
print(result)

если вы хотите mathEval в качестве вспомогательного средства, вам придется передать выражение как функцию, возвращающую значение выражения, так что вызов функции будет оценивать выражение; это позволяет отложить инициализацию. Вам придется использовать мощную функцию под названием setfenv, которая позволяет вам изменять окружение func; к сожалению, это было удалено в пользу _ENV в Lua 5.2 и более поздних версиях. Затем код становится тривиальным:

local function mathEval(func)
    setfenv(func, tbl)
    return func
end
mathEval(function() return sin(0)+cos(1)+2^2 end)

setfenv можно воспроизвести в Lua 5.2 с помощью библиотеки debug, поскольку Lua внутренне реализует _ENV как повышающее значение, как показано Leafo:

local function setfenv(fn, env)
  local i = 1
  while true do
    local name = debug.getupvalue(fn, i)
    if name == "_ENV" then
      debug.upvaluejoin(fn, i, (function()
        return env
      end), 1)
      break
    elseif not name then
      break
    end

    i = i + 1
  end

  return fn
end

'tbl = {} tbl.sin = math.sin tbl.cos = math.cos function myeval(exp) local prev_env = _ENV _ENV = tbl local result = exp _ENV = prev_env вернуть результат end myeval(sin(0))

mathsbeauty 11.01.2023 15:04

Я хочу использовать его вышеописанным способом. К сожалению, это не работает.

mathsbeauty 11.01.2023 15:04

Это проблема, о которой мы все упоминали, вы выполняете свое выражение ДО того, как что-либо передаете myeval. В этот момент грех не известен. Вы можете либо обернуть его в функцию, либо использовать первый подход, показанный LMD.

Luke100000 11.01.2023 16:27

Другие вопросы по теме