Напишите функцию (не полную программу), так что если функция вызывается с единственной глобальной переменной (или ближайшим эквивалентом вашего языка) в качестве аргумента, она выводит (то есть печатает или возвращает) имя этой переменной. Если аргумент не является переменной, выведите вместо него значение Falsey. (Вам не нужно обрабатывать случай, когда аргумент является переменной, но не глобальной.)
Не должно быть связи во время компиляции между вызовом функции и определением функции (в частности, определение функции не может быть макросом или подобной конструкцией, которая получает аргументы в форме литерального фрагмента исходного кода, ни в текстовом, ни в абстрактном синтаксическом дереве). форма). То есть: в языках, которые поддерживают раздельную компиляцию, программа должна работать, даже если вызов функции компилируется первым (без знания определения функции, но, возможно, с сигнатурой типа или эквивалентом), затем определение функции компилируется позже. Если у языка нет отдельной компиляции, тем не менее вы должны стремиться к аналогичному разделению между вызовом и определением.
Если вы используете скомпилированный язык, вы можете прочитать скомпилированную форму всей программы с диска и предположить, что программа была скомпилирована с отладочной информацией. (Таким образом, решения, которые работают, присоединяя отладчик из программы к себе, разрешены.)
Обратите внимание, что эта задача может быть невозможна на всех языках.
Примеры:
var apple = "Hello"
p(apple) // apple
var nil = "Nothing"
p(nil) // nil
var SOMETHING = 69
p(SOMETHING) // SOMETHING
function foo(){}
p(foo) // foo
p(3.14159) // false
p(function foo(){}) // false
источник
Ответы:
Джава
В настоящее время это работает с несколькими ошибками:
javac
с-g
флагом. Это генерирует всю отладочную информацию, включая имена локальных переменных в скомпилированном файле класса.com.sun.tools.javap
который анализирует байт-код файла класса и выдает читабельный результат. Этот API доступен только в библиотеках JDK, поэтому вы должны либо использовать Java-среду JDK, либо добавить tools.jar в ваш путь к классам.Теперь это должно работать, даже если метод вызывается несколько раз в программе. К сожалению, это еще не работает, если у вас есть несколько вызовов в одной строке. (Для того, который делает, см. Ниже)
Попробуйте онлайн!
объяснение
Эта первая часть получает некоторую общую информацию о том, в каком классе мы находимся и как называется функция. Это достигается созданием исключения и анализом первых двух записей трассировки стека.
Первая запись - это строка, в которую выдается исключение, из которой мы можем получить метод methodName, а вторая запись - это место, откуда была вызвана функция.
В этой строке мы выполняем исполняемый файл javap, который поставляется с JDK. Эта программа анализирует файл класса (байт-код) и выдает читабельный результат. Мы будем использовать это для элементарного "разбора".
Мы делаем несколько разных вещей здесь. Сначала мы читаем вывод javap построчно в список. Во-вторых, мы создаем карту строковых индексов байт-кода и строковых индексов javap. Это поможет нам позже определить, какой вызов метода мы хотим проанализировать. Наконец, мы используем известный номер строки из трассировки стека, чтобы определить, какой индекс строки байт-кода мы хотим видеть.
Здесь мы перебираем строки javap еще раз, чтобы найти точку, где вызывается наш метод и где начинается таблица локальных переменных. Нам нужна строка, где метод вызывается, потому что строка перед ним содержит вызов для загрузки переменной и определяет, какую переменную (по индексу) загрузить. Таблица локальных переменных помогает нам на самом деле искать имя переменной на основе индекса, который мы взяли.
Эта часть фактически анализирует вызов load, чтобы получить индекс переменной. Это может вызвать исключение, если функция фактически не вызывается с переменной, поэтому мы можем вернуть здесь ноль.
Наконец, мы анализируем имя переменной из строки в таблице локальных переменных. Возвратите ноль, если это не найдено, хотя я не видел причины, почему это должно случиться.
Собираем все вместе
Это в основном то, на что мы смотрим. В примере кода первый вызов - строка 17. строка 17 в LineNumberTable показывает, что началом этой строки является индекс строки 18 байт-кода. Это
System.out
нагрузка. Затем мы имеемaload_2
непосредственно перед вызовом метода, поэтому мы ищем переменную в слоте 2 LocalVariableTable, котораяstr
в этом случае.Для забавы, вот один, который обрабатывает несколько вызовов функций на одной строке. Это приводит к тому, что функция не является идемпотентной, но в этом вся суть. Попробуйте онлайн!
источник
System.out.println(e.getParamName(str));System.out.println(e.getParamName(str2));System.out.println(e.getParamName(str4));
на одна строка в ссылке TIO.javap
местоположение , как это:Paths.get(System.getProperty("java.home"), "bin", "javap")
.Python 2
Это самый грязный код, который я написал, но он работает. ¯ \ _ (ツ) _ / ¯ Выдает ошибку несуществующей переменной, так как Python сразу не понравится вам за вызов функции с одним из них. Также выдает ошибку для не-переменных, но это может быть исправлено с помощью try /, за исключением случаев, когда это необходимо.
Попробуйте онлайн!
Если нам разрешено принимать аргумент в виде строки, это удовлетворяет требованиям вывода ложного значения на неверный ввод.
Попробуйте онлайн!
источник
Mathematica
HoldFirst
Атрибут предотвращаетf
от оценки его аргумента перед вызовом функции.ValueQ @ x
затем проверяет, является ли данный аргумент переменной, которой было присвоено значение. Если нет, мы просто вернемсяFalse
из-за короткого замыкания. В противном случае мы получаем имя переменной с помощьюToString @ HoldForm @ x
.источник
And
... Мне нравится, что правильный аргументAnd
даже не должен быть логическим выражением.f[x_] := ValueQ @ x && HoldForm @ x
? Если бы не требование проверять, является ли входная переменная,HoldForm
сама по себе будет работать.HoldAll
вместоHoldFirst
?HoldForm[a]
а не"a"
. Хотя они отображаются одинаково в записной книжке Mathematica, функция существует независимо от внешнего интерфейса, поэтому я хотел иметь решение, которое возвращает строку.Mathematica
Mathematica любит оценивать все , поэтому, чтобы остановить это, мы должны бороться с этим. На своем родном языке.
Как?
Сообщает Mathematica, что всякий раз, когда
f
вызывается функция , ее аргументы не должны оцениваться (т.е. храниться).Когда
f
вызывается с аргументом, выведитеFalse
. (?!)когда
f
вызывается с определенным символом (который имеет значение), выведите имя символа для ввода.Предыдущая строка не имеет приоритета, несмотря на то, что она была определена ранее, потому что это определение более конкретное. Как сказано в документации Wolfram: Mathematica «пытается поставить конкретные определения перед более общими определениями».
Mathematica очень упряма и старается по мере возможности оценивать переменные. Дополнительный
Unevaluated
заботится об этом.источник
C #
Полная / Отформатированная версия:
Другой способ сделать это - отразить тип следующим образом:
Тем не менее, вы должны назвать это как:
Затем он также завершается неудачно
3.14159
, возвращаясь,Length
и для этого вам также нужно вызвать его следующим образом:В C # 6.0 мы также имеем:
Но это не скомпилируется, если вы передадите ему что-то, что не является переменной, например
3.14159
. Я считаю, что он также оценивает входные данные во время компиляции, поэтому кажется, что он также не соответствует этому требованию.источник
Expression
). Вы также должны считатьusing System.Linq.Expressions;
.MATLAB
Внутри функции есть несколько предустановленных переменных, таких как
varargin
илиnargin
, среди тех, которые у нас также естьinputname
.украден отсюда
источник
x=42;y=54; f=@(x)eval(inputname(1));f(x),f(y)
eval==evil
= D (это на самом деле работаетx=42;y=54; f=@(x)eval('inputname(1)');f(x),f(y)
)x
, а затемeval
- аргумент функции, а не переменную рабочей области.р
substitute
возвращает дерево разбора для неоцененного выражения. Вidentical
условном убеждается , что это невычисленное выражение не совпадает с самим выражением; то есть передаваемый параметр не является литералом.источник
Python 2
Некоторое исследование было сделано. И это кажется возможным в python, но я все еще ожидаю, что будут найдены некоторые проблемы.
Решение не идеальное, так как предполагает некоторую структуру кода. И все же я не сломал его до сих пор.
Он использует inspect для просмотра объема окружения и определения места вызова функции
get_name
. Напримерinspect...[1]
вернетсяИ
inspect...[1][4]
покажет нам список с кодом, где вызывается функция:После этого я использовал регулярное выражение для получения имени аргумента
И
.lstrip().rstrip()
удалить все пробелы, которые могут быть помещены в скобки.Пример с некоторым хитрым вводом
источник
PowerShell
Но это не работает надежно, это элементарно.
источник
PHP
Необходимо, чтобы значение переменной было уникальным в массиве глобальных переменных
Попробуйте онлайн!
PHP , 96 байт
Попробуйте онлайн!
Необходимо, чтобы переменная инициализировалась непосредственно к вызову функции.
Проверяет, равна ли последняя глобальная переменная передающей переменной
источник
JavaScript (ES6)
Для всех имен свойств в
window
(Object.getOwnPropertyNames(w)
) попытайтесь определить метод получения для этого свойства, который возвращает имя свойства.Затем добавьте запись на карту,
M
где ключом является (возможно, переопределенное) значение свойства, а значением является имя свойства.Функция
f
просто принимает переменную (т.е. свойствоwindow
) и возвращает записьM
для этого значения.Это работает для всех встроенных глобальных переменных, кроме
window
самого себя, поскольку нет способа отличить его отtop
(если только он не выполняется во фрейме):источник
L not a function
. Почему это случилось?Perl 5 + Devel :: Caller
Мы используем Devel :: Caller (подобный отладчику модуль) для обхода стека вызовов, поиска вызова функции и возврата всех операндов в аргументе, возвращая их как имена переменных. Если есть больше (или меньше) чем один операнд, мы не были вызваны с переменной. Если операнд не был переменной, у него не будет имени, и мы тоже можем это обнаружить.
Самый хитрый случай, если мы получим выражение с одним операндом, включающее переменную, такую как
~$x
. Мы можем выяснить, произошло ли это, взяв ссылку на переменную непосредственно из таблицы символов (используя${…}
синтаксис символьной ссылки) и сравнив ее адрес в памяти со значением, которое мы передали в качестве аргумента (который, как правило, передается по ссылке). ). Если они разные, у нас есть выражение, а не одиночная переменная.Обратите внимание, что если мы вызываем эту функцию с выражением preincrement или precrement для одной переменной, как в
v(--$x)
, мы получаем$x
возвращаемое значение. Это потому, что на самом деле это сама переменная, которая передается в функцию; он просто увеличивается или уменьшается заранее. Я надеюсь, что это не дисквалифицирует ответ. (В некотором смысле это делает его лучше, потому что он показывает, что мы проверяем сам аргумент, а не просто читаем исходный код.)источник
PHP
В то время как другие представления PHP только проверяют, соответствует ли данное значение глобальному значению, эта версия работает, принимая ссылку на значение:
Теперь это должно работать, даже если глобальная переменная является ссылкой на другое значение во время вызова.
Проверьте это здесь .
источник
Röda
Попробуйте онлайн!
Röda имеет встроенную функцию для этого -
name
. К сожалению, тем не менее, он не возвращает ложное значение, когда не задана переменная.Этот код использует несколько функций семантики ссылок. Объяснение построчно:
f(&a...) {
Функция принимает переменное число ссылочных аргументов (
&a...
). Это единственный способ в Röda создать список ссылок.a() | name(_) | for str do
Во второй строке элементы
a
помещаются в поток (a()
). Эти элементы являются ссылками, если функции были заданы переменные и нормальные значения в противном случае.Элементы повторяются с помощью подчеркивания. Синтаксис подчеркивания является синтаксическим сахаром для
for
циклов, поэтомуname(_)
эквивалентенname(var) for var
. Имя переменной, используемой вfor
цикле, имеет форму,<sfvN>
где N изменяется. (Т. Е. "name(<sfv1>) for <sfv1>
") Запрещено, чтобы пользовательская переменная содержала<
или>
, поэтому сгенерированные имена не конфликтуют с существующими именами переменных.name()
Функция возвращает имя данной переменной. Если элемент вa
итерации является ссылкой, то это переменная, даннаяname
. В противном случае, если элемент имел нормальное значение, переменная, которая указана,name
является переменной подчеркивания<sfvN>
. Это связано с семантикой ссылок в Röda: если функция принимает ссылку, и функции передается ссылочная переменная, переданное значение указывает не на ссылочную переменную, а на переменную, на которую указывает ссылочная переменная.false if [ "<" in str ] else [str]
В третьей строке мы проверяем, содержит ли имя переменной в потоке
<
символ. Если это так, то это переменная подчеркивания, и переданное значениеf
не является ссылкой. В противном случае мы выводим имя ссылки.Это решение не работает, если переменная, переданная функции, является ссылкой или подчеркиванием. Тем не менее, вопрос указывает, что должны обрабатываться только глобальные переменные, и они не могут быть ссылками или подчеркиванием переменных в Röda.
источник
Рубин , 46 байт
Похоже на самый грязный код, который я когда-либо писал для Ruby.
Требует, чтобы вызываемые вами глобальные переменные имели уникальное значение, которого нет ни в одной другой глобальной переменной, потому что единственный способ решить эту проблему в Ruby - это выполнить поиск по всем глобальным переменным и вернуть первое совпадение. ОП говорит, что все в порядке, и вправе судить, действительно ли мое решение действительно.
Обратите внимание, что глобальные переменные начинаются с
$
Ruby, если вы хотите добавить дополнительные контрольные примеры.Попробуйте онлайн!
источник
PHP
если значение найдено, выведите имя переменной и выйдите. ничего не печатать и больше не выходить.
61 байт для возврата имени переменной или
NULL
:Он не найдет именованные функции, только те, которые назначены переменным.
И функция PHP не может определить, был ли параметр предоставлен по ссылке или по значению. Функция просто вернет имя, где значение соответствует значению параметра функции.
Протестируйте это онлайн
источник
PowerShell
Новая версия, но работает начиная с PowerShell 3.0
Попробуйте онлайн!
Предыдущая версия
Попробуйте онлайн!
источник
TCL
демонстрация
источник
JavaScript (ES6)
Требует, чтобы значение переменной, переданной функции, было уникальным для этой переменной. Возвращает,
undefined
если переменная не была передана.Попытайся
По какой-то причине он генерирует ошибку перекрестного происхождения в фрагменте, когда передается «литерал».
объяснение
Переберите все записи в глобальном объекте (
this
), проверяя, строго ли равно значение каждого из них значению аргумента, переданного функции. Если соответствующая запись найдена, возвращается ее ключ (имя), выход из функции.альтернатива
С теми же требованиями, что и выше
источник
hello--
). Кроме того, вам нужно использовать,var
а неlet
.let
иvar
. На ваш второй вопрос: это произошло потому, что у вас есть переменная с именемIN_GLOBAL_SCOPE
в вашей глобальной области видимости, и она имеет значение1
. Вы можете проверить существующие переменные в вашей глобальной области видимости и их значения, выполнив это перед тестированием выше:for(x in this)console.log(x+": "+this[x])
Swift, 45 байт
источник
value of type 'Mirror' has no member 'label'