Здравствуйте, Real 3L0, Вы писали:
R3>В качестве одного из преимуществ языка приводится то, что его легче читать.
R3>Где-то это явно видно, но где-то — мне ещё пока трудно перестроить мышление.
Как часто бывает нашей жизни преимущества порождают и недостатки.
R3>1. Непревычно, что начало точки разбора функции, по сути, находится в самом конце. Ну, тут причина понятна, это я просто брюзжу.
Не, на самом деле так оно и есть. С одной стороны то что функции объявляются перед их использованием действительно мешает изучать код основной функции. Но с другой это позволяет использовать в таких функциях замыкания.
Но этот недостаток нивелируется при использовании IDE. В VS локальные функции по умолчанию свернуты и тот же самый код будет выглядеть так:
def lexer(text : string) : list[Token]
{
mutable index = 0;
+ def peek() : char
+ def read() : char
+ def isDigit(ch) { ch >= '0' && ch <= '9' }
+ def loop(resultTokens : list[Token]) : list[Token]
loop([])
}
Для изучения конкретной функции просто нажимаем на "+" и получаем что-то вроде:
def lexer(text : string) : list[Token]
{
mutable index = 0;
+ def peek() : char
+ def read() : char
+ def isDigit(ch) { ch >= '0' && ch <= '9' }
- def loop(resultTokens : list[Token]) : list[Token]
{
+ def number(ch : char, accumulator : int = 0) : int
+ def error()
def ch = read();
match (ch)
{
| ' ' | '\t' => loop(resultTokens) // игнорируем пробелы
| '+' | '-' | '*' | '/' => loop(Token.Operator(ch.ToString()) :: resultTokens)
| '\0' => resultTokens.Reverse()
| _ when isDigit(ch) => loop(Token.Number(number(ch)) :: resultTokens)
| _ => error()
}
}
loop([])
}
и так далее.
R3>2. Непревычно, что новые элементы в список resultTokens добавляются с начала, что приводит к необходимости переворачивать список. Я, конечно, понимаю, что пример специальный, но не мог бы кто-нибудь преобразовать функцию так, чтобы новые элементы в resultTokens добавлялись в конец? Если это возможно. (Не обязательно дословно точно.)
Это уже особенность не языка, а структуры данных list[T]. Она так же вела бы себя и в любом другом языке. Все без исключения ФЯ имеют подобную структуру данных. Ее главная особенность — она неизменяемая. Однажды создав список они останется таковым до того момента когда GC его соберет за ненадобностью. А в функциональном коде неизменяемость — это большое достоинство. Кроме того неизменяемость позволяет порождать из одного списка другой не создавая его копии.
Следующим достоинством является константное (О(1)) время вставки.
Но все это возможно только в следствии того, что список строится от хвоста к голове.
Очень часто это даже является преимуществом. Но при сборке списка его приходится разворачивать.
В большинстве случаев это не является проблемой. К тому же зачастую список обрабатывается не по одному разу и он сам собой разворачивается. А иногда вообще не важен порядок элементов.
Ну, и в конце концов никто не запрещает использовать и другие типы данных. Например System.Collections.Generic.List[T].