10.02.2017, 21:45 | #41 |
Moderator
|
Она и для фибоначчи замечательно выполняется:
X++: (define (fib n) (fib-iter 1 0 n)) (define (fib-iter a b count) (if (= count 0) b (fib-iter (+ a b) a (- count 1)))) |
|
10.02.2017, 21:55 | #42 |
Moderator
|
И, извини, но я все-таки спрошу:
Цитата:
может, просто приведешь пример?
ну, или ссылки хотя бы ))) Цитата:
Для факториала как раз замечательно выполняется оптимизация хвостовой рекурсии даже вручную. На собеседовании могут давать факториал, а могут давать фибоначчи ))))
.... бывает, конечно, когда кандидат не врубается и предлагает "удалиться". что ж... в этом случае вряд ли такому кандидату стоит задавать другие вопросы. |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
10.02.2017, 22:09 | #43 |
Участник
|
Цитата:
собственно возвращаемся к моему посту: Цитата:
Сообщение от mazzy
тут дело даже не в функциональном языке или процедурном.
тут дело в ленивых вычислениях. ... именно ленивые вычисления и отсутствие побочных эффектов и позволяют так легко использовать рекурсию. ... обрати внимание, что для линейной оценки времени выполнения достаточно хранить только два числа последовательности Фибонначи. а для меньшей оценки (f(n) < On(n)) достаточно хранить только три числа. и вот я совсем не уверен, что оптимизация сработает с таким выражением. И именно эта ленивость и позволяет избавиться от повторных вычислений, не так ли? ленивость и отсутствие побочных эффектов. Если бы подобная ленивость была бы в обычном языке, то... Сейчас в .net вводят LINQ и Lazy-интерфейсы... это конечно не то, но достаточно близко... можешь рассказать подробнее как "это" работает? Цитата:
не... я надеялся, что ты расскажешь всем. у тебя это хорошо получается. кроме того, здесь есть и другие функциональщики, которые могут подключиться к обсуждению. в свое время я тебя приглашал, но у тебя была более привлекательная работа. до сих пор жалею, что тогда не смог предложить тебе лучшие условия. |
|
10.02.2017, 22:24 | #44 |
Moderator
|
Цитата:
А в функциональном языке ленивое выражение (+ a b) будет в стеке n раз ))))
и вот я совсем не уверен, что оптимизация сработает с таким выражением. И именно эта ленивость и позволяет избавиться от повторных вычислений, не так ли? ленивость и отсутствие побочных эффектов. Половина функциональных языков программирования принципиально не поддерживают ленивость. Вот от слова "вообще". Нет ее там. А в тех языках где есть - я 10 раз подумаю, прежде чем ее использовать. Потому что в языках с поддержкой ленивых вычислений надо четко представлять, где и в какой момент это вычисление произойдет. А иначе оно произойдет в самый непоходящий для пользователя момент (в виде проблем с производительностью). Нет в моем примере никакой ленивости. Теперь побочные эффекты. Их здесь нет, но если этот код переписать на C# или Java - их тоже не появится. Им просто не откуда здесь взяться. Ну и вообще, если говорить про функциональные языки программирования - то из тех, что используются в production я знаю только 1 - haskell. Все остальные функциональные языки программирования допускают побочные эффекты. Цитата:
А в функциональном языке ленивое выражение (+ a b) будет в стеке n раз ))))
Я же описал выше, что произойдет При очередном рекурсивном вызове три параметра со стека будет сниматься и три добавляться. По сути - будет просто происходить их замена. Цитата:
можешь рассказать подробнее как "это" работает?
Все равно не понятно ? |
|
10.02.2017, 22:25 | #45 |
Участник
|
Получается, что тот кусок кода, который я написал вчера ночью за две минуты, укладывая сына спать, не имея Аксапты под рукой, добавил мне минус в карму?
|
|
10.02.2017, 22:33 | #46 |
Moderator
|
Можно еще вот так попробовать расписать - вызовы функций, как они будут происходить
X++: fib 5 fib-iter 1 0 5 fib-iter 1 1 4 fib-iter 2 1 3 fib-iter 3 2 2 fib-iter 5 3 1 fib-iter 8 5 0 -> 5 Обрати внимание, что каждый последующий вызов - он самодостаточен. То есть. когда fib-iter 8 5 0 вернет 5-ку ему эту 5-ку надо просто вернуть, а не делать с ней что-то еще вверх по стеку вызовов. Это потому, что у нас последний вызов в функции выглядит так: X++: (fib-iter (+ a b) a (- count 1)))) X++: a + (fib-iter (+ a b) a (- count 1)))) Вот. Все - лучше мне уже на форуме не объяснить p.s. Цитата:
И именно эта ленивость и позволяет избавиться от повторных вычислений, не так ли?
Цитата:
обрати внимание, что для линейной оценки времени выполнения достаточно хранить только два числа последовательности Фибонначи. а для меньшей оценки (f(n) < On(n)) достаточно хранить только три числа.
Последний раз редактировалось Андре; 10.02.2017 в 22:41. |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
10.02.2017, 23:01 | #47 |
Участник
|
Маззи, пожалуйста не приводите мой код как пример дешевого программиста
Я выскочка с гуманитарным образованием. Для людей с неправильным происхождением свойственно натыкаться на грабли на пути к совершенству. Сейчас я понял, что моя вчерашняя попытка написать пример была ошибкой. Но из-за некоторых таких попыток мне все-таки удалось кое-чего достичь в жизни. И я пока еще выживаю в конкурентной борьбе. Я готов быть аутсайдером в окружении богов. Готов получать 500 тыс рублей среди людей, которые получают миллион рублей. Поэтому и встреваю в беседы великих |
|
|
За это сообщение автора поблагодарили: mazzy (2), ax_mct (5). |
10.02.2017, 23:13 | #48 |
Участник
|
Цитата:
т.е. от повторных вычислений можно избавиться и в обычных процедурных языках? что-то типа такого Код: public var fib(var n) { fibb-iter(1, 0, n); } private var fib-iter(var a, var b, var n) { if(n <= 0) return b; else return fib-iter(a+b, b, n-1); } правда без "оптимизации хвостовой рекурсии" рекурсивные вызовы ограничены размером стека. а с оптимизацией стек вообще расти не будет. так? чертовы функциональщики... ))))) а разве функциональный язык не разворачивает всю эту байду в символьное супер-выражение, которое будет вычислено на самом последнем этапе? |
|
10.02.2017, 23:15 | #49 |
Участник
|
Цитата:
может, зря я на него бочку качу... |
|
10.02.2017, 23:24 | #50 |
Moderator
|
Цитата:
и получаем линейное, а не экспоненциальное время выполнения. и никаких повторных вычислений.
правда без "оптимизации хвостовой рекурсии" рекурсивные вызовы ограничены размером стека. а с оптимизацией стек вообще расти не будет. так? Цитата:
а разве функциональный язык не разворачивает всю эту байду в символьное супер-выражение, которое будет вычислено на самом последнем этапе?
|
|
|
За это сообщение автора поблагодарили: mazzy (2). |
10.02.2017, 23:32 | #51 |
Участник
|
Маззи, а как вам такой вариант?
X++: static void Job46(Args _args) { int j; real fibonaci(int n) { real first = 0; real second = 1; real result = 0; int i; for (i = 0; i < n; i++) { result = first + second; second = first; first = result; } return result; } ; for (j = 0; j < 50; j++) { info(strfmt("%1", fibonaci(j))); } } |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
10.02.2017, 23:32 | #52 |
Участник
|
Цитата:
ваш кусок кода выполняет вычисления за один проход без повторных вычислений. что является достижением. и потребляет фиксированную память. вот только int32 и панковский while(true)... ну и int2str... живите теперь с этим. )))) |
|
10.02.2017, 23:35 | #53 |
Участник
|
|
|
10.02.2017, 23:38 | #54 |
Участник
|
вложенные то циклы зачем? раньше был один. и это было хорошо.
и снова и магическая константа в коде... константу-то можно было бы и прокомментировать. с real другая байда. с некоторого члена последовательности, числа становятся неточными. если разработчик выбирает real, то было бы хорошо, если бы он предупредил об относительных погрешностях и примерно с какого числа начинаются значимые погрешности на real. ну или хоть обозначил бы что такая проблема есть, а число и погрешность надо посчитать постановщику. заодно это и было бы обоснованием для магической константы )))) Последний раз редактировалось mazzy; 10.02.2017 в 23:44. |
|
10.02.2017, 23:49 | #55 |
Участник
|
Цитата:
Константа 50 - тоже для наглядности. Просто красивое число для примера вывода первых 50 членов последовательности. |
|
|
За это сообщение автора поблагодарили: mazzy (2). |
10.02.2017, 23:52 | #56 |
Moderator
|
Прошу прощения, но не удержался:
X++: let fibonacci = Seq.unfold (fun (x, y) -> Some(x, (y, x + y))) (0I,1I) fibonacci |> Seq.take 50 Последний раз редактировалось Андре; 11.02.2017 в 00:04. |
|
11.02.2017, 00:02 | #57 |
Участник
|
Some? почему some?
вернее, а что значит Some в данном контексте? и почему целые 0, 1? а целые в F# скольки разрядные? как F# относится к переполнению целого? я не то, чтобы хотел. я опасался, что построенное супер-выражение в стек ляжет. причем лобовое решение fib(n-1)+fib(n-2) скорее всего быстро переполнит стек и в функциональном языке за счет повторных подстановок в результирующее супер-выражение. |
|
11.02.2017, 00:51 | #58 |
Участник
|
int - 32 разряда
суффикс I означает bigInt some(a,b) означает some(tuple(a,b)), что означает nullable tuple(a,b) tuple(a,b) в контексте функции unfold означает: a - текущее состояние, b - следующее состояние. так? ахренеть! еще фибоначчи на F# https://msdn.microsoft.com/en-us/vis...n-%5Bfsharp%5D http://www.blogs.sigristsoftware.com...-Sequence.aspx мдя... ========================= а как это ленивое чудо потребляет память? |
|
11.02.2017, 07:11 | #59 |
Moderator
|
Цитата:
int - 32 разряда
суффикс I означает bigInt some(a,b) означает some(tuple(a,b)), что означает nullable tuple(a,b) tuple(a,b) в контексте функции unfold означает: a - текущее состояние, b - следующее состояние. так? ахренеть! 0I,1I - как ты правильно заметил, что BigInteger, а точнее, обертка вот над этой .NET структурой: https://msdn.microsoft.com/ru-ru/lib...v=vs.110).aspx Цитата:
The T:System.Numerics.BigInteger type is an immutable type that represents an arbitrarily large integer whose value in theory has no upper or lower bounds.
X++: fun (x, y) -> Some(x, (y, x + y)) Эта функция (как видно по ее названию) противоположна более популярной функции fold (которая в python называется reduce, а в C# LINQ - aggregate): Цитата:
Seq.fold (fun acc elem -> acc + elem) 0 seq
Цитата:
seq.Aggregate(0, (acc, elen) => acc + elem);
Теперь про Some - я там выше написал, что эта функция "постарается" вернуть очередное значение. Но компилятор понимает, что это не всегда возможно. И хочет, чтобы ты это понимал и не забывал и предлагает использовать тебе "option type" - аналог монады MayBe из других языков программирования. |
|
11.02.2017, 08:52 | #60 |
Участник
|
|
|