почему в выражениях Lua нет анонимных функций? - PullRequest
0 голосов
/ 02 августа 2020

Может ли кто-нибудь объяснить мне, почему конструкция анонимной функции в Lua не является полноценным выражением? Мне это кажется странным: это (немного) противоречит идее о том, что функции должны быть объектами первого класса, и является (не часто, но иногда) неудобством для того, что в основном является действительно хорошо продуманным и элегантным языком.

пример, используя командную строку Lua, с обходным путем

Lua 5.3.3  Copyright (C) 1994-2016 Lua.org, PUC-Rio
> function(x) return x*x end (2)
stdin:1: <name> expected near '('
> square = function(x) return x*x end
> square(2)
4

Ответы [ 3 ]

3 голосов
/ 02 августа 2020
Синтаксис вызова функции

Lua имеет встроенный c сахар. Вы можете вызывать функции с помощью трех элементов:

  • Список значений в скобках.
  • Конструктор таблицы (функция принимает таблицу как единственный аргумент).
  • Строковый литерал.

Lua хочет быть несколько регулярным в своей грамматике. Итак, если есть вещь, которую вы можете вызвать как функцию одним из этих способов, то должна иметь смысл иметь возможность вызывать ее любым из этих способов.

Рассмотрим следующий код:

local value = function(args)
   --does some stuff
   end "I'm a literal" .. foo

Если мы разрешаем вызывать произвольные выражения без скобок, как и любой другой вызов функции, то это означает создание функции, ее вызов с помощью строкового литерала, объединение результата этого вызова функции с foo и сохранить это в value.

Но ... действительно ли мы хотим, чтобы работало? То есть, хотим ли мы, чтобы люди могли написать это и чтобы он был действительным Lua код?

Если такой код считается неприглядным или запутанным, есть несколько вариантов.

  1. Lua может просто не иметь вызовов функций со строковыми литералами. В конце концов, вы сохраняете только 2 круглые скобки. Возможно, даже не разрешить конструкторы таблиц, хотя они менее неприглядны и гораздо менее запутаны. Заставьте всех использовать круглые скобки для всех вызовов функций.
  2. Lua может сделать так, чтобы только в случаях лямбда-выражений не выполнялись вызовы функций со строковыми литералами. Это потребует существенной отмены регуляризации грамматики.
  3. Lua может заставить вас заключить в скобки любую конструкцию, в которой вызов функции не является явно предполагаемым результатом предыдущего текста.

Кто-то может возразить, что table_name[var_name] "literal" уже довольно сбивает с толку относительно того, что происходит. Но опять же, предотвращение этого потребует отмены регуляризации грамматики. Вам придется добавить во все эти особые случаи, когда что-то вроде name "literal" является вызовом функции, а name.name "literal" - нет. Таким образом, вариант 2 отсутствует.

Возможность вызова функции со строковым литералом вряд ли ограничена Lua. JavaScript может это сделать , но вы должны использовать специальный c буквальный синтаксис, чтобы его получить. Кроме того, возможность набрать require "module_name" кажется хорошей идеей. Так как такие вызовы считаются важной частью синтаксиса c сахара, поддерживаемого несколькими языками, вариант №1 отсутствует.

Итак, ваш единственный вариант - №3: заставить людей заключать в скобки выражения, которые они хотят вызвать.

1 голос
/ 02 августа 2020

Короткий ответ

Для вызова функции выражение функции должно быть либо именем, либо индексированным значением, либо другим вызовом функции, либо выражением в круглых скобках.

Длинный ответ

Я не знаю, почему это так устроено, но я просмотрел грамматику , чтобы точно узнать, как это работает. Вот запись для вызова функции:

functioncall :: = prefixexp args | prefixexp ':' Имя args

«args» - это просто список аргументов в круглых скобках. Соответствующая часть - «prefixexp».

prefixexp :: = var | functioncall | '(' exp ')'

Хорошо, теперь мы можем вызвать еще один «вызов функции». «exp» - это обычное выражение:

exp :: = nil | ложь | правда | Цифра | LiteralString | '...' | functiondef | prefixexp | настольный конструктор | exp binop exp | unop exp

Таким образом, мы можем вызывать любое выражение, если оно заключено в круглые скобки. "functiondef" охватывает анонимные функции:

functiondef :: = function funcbody

funcbody :: = '(' [parlist] ')' конец блока

Итак, анонимная функция - это выражение «exp», но не «prefixexp», поэтому нам нужны круглые скобки вокруг него.

Что такое «var»?

var: : = Имя | prefixexp '[' exp ']' | prefixexp '.' Имя

«var» - это либо имя, либо индексированное значение (обычно таблица). Обратите внимание, что индексированное значение должно быть "prefixexp", что означает, что строковый литерал или конструктор таблицы должны быть в круглых скобках, прежде чем мы сможем их проиндексировать.

В итоге: вызываемая функция должна быть либо именем, либо индексированное значение, вызов функции или какое-либо другое выражение в круглых скобках.

Большой вопрос: почему «prefixexp» обрабатывается иначе, чем «exp»? Я не знаю. Я подозреваю, что это как-то связано с сохранением вызовов функций и индексацией вне обычного приоритета оператора , но я не знаю, зачем это нужно.

0 голосов
/ 02 августа 2020

Понятно ... нужны круглые скобки, извините.

(function(x) return x*x end) (2)

Я до сих пор не понимаю, почему он так устроен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...