Эээ, почему не эффективно? Для чего тогда придумывалась вся эта функциональщина в паскале, если все оно не эффективно? Опять же если не эффективно, то в какой части и по сравнению с чем? Если сравнить тот же перебор в цикле по всем K от 1 до какого-то числа, это будет намного эффективней? Ну да, маленький мальчик Гаусс решил задачку эффективно, но это не везде такое возможно. Да и что же, над каждой задачей сидеть и ломать голову, как можно ее решить наиболее эффективно? Может мне не важна эффективность в данном случае. Вот мне бы, в первую очередь, хотелось бы поменьше кода и побольше ясности. А потом уже можно и об эффективности подумать.
А в чем преимущество использования First перед Take?
Тренировки все же лучше устраивать там, где получаешь какое-то преимущество. То, что функциональное программирование (в основе которого лежит рекурсия) позволяет реализовать итерационный алгоритм, построенный на базе цикла, известно и доказано (рекурсия и итерация взаимозаменяемы, хоть и с разной степенью эффективности). Но функциональное программирование ради функционального программирования - это не просто глупость, это - зло. Функциональное программирование хорошо там, где запись алгоритма выглядит проще и понятнее. Для данной задачи понятнее цикл, даже если не говорить о какой-то там эффективности. Поэтому хорош тот язык, где можно функциональную парадигму использовать там, где ей место, а не везде.
.First - это .Take(1), .Last - это .TakeLast(1)
Никаких преимуществ, кроме более короткой записи.
По скорости последовательности всегда хуже обычных циклов. Хотя бы потому что делается полно вызовов подпрограмм. А ещё создаются объекты в куче (последовательности это классы). В то время как в циклах память вообще не выделяется (используется из стека, а там все выделено при старте программы).
Придумывалось оно чтоб сократить код и сделать его более понятным.
Вот только в данном случае вы ни того ни того не получите через последовательности. Вот, к примеру, математическое решение:
begin
var res := sqrt(1+8*ReadlnInteger('N ='))/2 - 0.5;
Ceil(res).Print;
end.
А через циклы вы сами делали, и выглядит оно даже понятнее функционального решения.
Бред.
В нулевых
У них возвращаемое значение разное, .Take не заменит .First если вам надо вызвать для результата что то кроме .Print.
Во первых, .Take-и создают ещё 1 класс-последовательности, который ещё раз нужно перебирать. Лишние затраты на вызовы.
Во вторых MoveNext (код выбирающий перебирать ли элементы дальше) - более сложный и затратный.
В третьих - я сейчас посмотрел в .TakeLast, и это отборные костыли, как хуже реализовать - и придумать сложно. (#1678)
Ваше “костыли” настолько примелькалось. что я уже не обращаю внимания на это слово. Это как когда какой-то человек, к примеру, постоянно матерится, на мат через какое-то время внимание просто перестаешь обращать, понимая, что это у него идет от невоспитанности. Как Ваши посты почитать - ну весь PascalABC.NЕТ - один большой костыль. Ну напишите уж лучше, что ли, раз Вы настолько большой специалист.
Где-то заменит, где-то - нет. Надо смотреть по алгоритму решения, что именно требуется.
Скажем, повторное вычисление сумм, которое спрятано в Select – неэффективно. “Функциональщина”, как Вы выражаетесь, придумана для тех, кто хочет написать короткий и понятный код, не слишком заботясь о наивысшей скорости выполнения программы. Вы сами должны выбирать инструмент под свои задачи, никто это за Вас не сделает. Вас же не смущает, что есть и ложка, и вилка, и что вилкой суп есть не очень удобно И это не повод отказываться от вилки.
Это собирать грибы лучше там, где они растут. А искать можно везде, главное, чтобы пейзаж нравился Если же серьёзно, не вижу причин, почему бы не поупражняться и без получения преимущества. При обучении все бонусы – это новые нейронные связи Повторюсь: если сам понимаешь, где достоинства, а где недостатки решения.
“Если внутри функции не присвоить переменной Result некоторое значение, то функция вернет в результате своего вызова непредсказуемое значение.”
Но я, почему-то, ни разу не встречал, чтобы функция возвращала это непредсказуемое значение, если не инициализировать Result. Например:
function foo(): boolean;
begin
end;
begin
Loop 1000 do Print(foo())
end.
1000 раз возвращает False (или 0, или пустую строку, или nil, при других возвращаемых типах). И ни разу, в этом случае, не возвращает True. Так нужно ли инициализировать Result?
Немножко. Вот тут все понятно, почему разные адреса:
procedure P(n: integer);
begin
if n > 10 then exit;
var x: byte;
Writeln(x, ' ', @x);
P(n + 1)
end;
begin
P(1)
end.
Потому что на стеке 10 подпрограмм со своими переменными x. А в том случае в цикле, на любой итерации, на стеке лежит только одна P(). И не понятно, почему переменной x каждый раз дается один и тот же адрес. Других адресов в памяти нет, что ли?
Стек это не куча, на нём всё лежит в определённом порядке, а точнее в том - в котором были вызваны методы (сначала старые, потом новые).
У вас в самом начале идёт ваша Main (begin-end.). Потом P. Когда P завершается - указатель конца стека просто сдвигает назад к Main. Затем снова вызывается P, и её кладёт снова прямо после Main.
А все локальные переменные каждого метода всегда выделяются в момент вызова, в порядке их описания в IL, которое решает компилятор паскаля и только 1 раз, перед созданием .exe .