Pull to refresh
10
0
Send message

как оно внутри

Вы путаете язык и реализацию (компилятор и т.д.). Один и тот же язык может иметь разные реализации. Даже если вместо процессора будет сидеть человек со счётами, на выразительности языка это никак не скажется.

в реализации рекурсия сводимая к итерациям ВСЕГДА к ним сводится

Неверно.

потому что итерации ВСЕГДА дешевле

Не вижу никакой разницы по производительности между циклом и хвостовым вызовом.

но к тому моменту он был в пяти других языках

В каких?

приехало из, например, Js, Java, Perl, Python

Когда в перечисленных Вами языках когда async/await появился?

а потому если можно рекурсию преобразовать к циклам так и поступают

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

«переменная» — это любое место, куда можно что‑то положить, и потом это оттуда же взять

То есть, глядя на код, нельзя сказать, сколько там определено переменных? А HelloWorld содержит как минимум 16 переменных (основные регистры)? Даже не 16, а .... (добавить стек и т.п.).

с точки зрения обсустройства памяти различия небольшие (или их вовсе нет)

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

ваш Хацкель совершенно ни при чём, даже если в нём есть похожий паттерн, это не означает, что именно он является прототипом

Этот паттерн изначально появился в виде "выражения вычисления" (способ задавать монады) в функциональном F#. Через 4 года его добавили в C#. Читайте историю.

пайп функций это именно функциональный стиль. Он описан ещё в старых книжках по Лиспу Хювенена/Сапеняна в 1985-88 годах (ЕМНИП).

Вы ссылаетесь на Лисп без указания контекста, как будто всё, что есть в Лиспе (включая defvar), это "функциональщина".

не помню чтобы мы где-то соревновались

Мы не соревновались, мы сравнивали.

Я привёл код на F#. Вы привели описание на пёрл/пхп. Судя по описанию, Ваш код длиннее. А судя по упоминанию регулярных выражений, при небольшом усложнении задачи (например, "вернуть тип, который встречается в таблице чаще") Ваш код значительно усложняется.

я сделал второй шаг, введя вторую функцию

Мой шаг обладает общностью. Ваш шаг перестаёт работать, когда в программе встречается ветвление.

Вам не кажется?

Тот, кто паял схемы на диодах, не может ошибаться?

а об одном в отрыве от другого говорить нельзя

Можно и нужно, если мы говорим о языке программирования, а не о языке вместе с "окружением" (библиотеки, сообщество, эффективность компилятора и т.п.).

У Вас же получается, что один и тот же язык то хороший, то плохой.

соответственно из-за этого хвостовые рекурсии "оптимизируют" обратно в процедурный стиль

Не имеет значения, во что это превратит компилятор. Более того, компилятор может транслировать функциональный код в код на Си (да-да, с циклами), чтобы получить возможность использовать сторонний компилятор для языка Си, имеющий 100500 оптимизаций для десятков различных процессоров.

здесь де-факто конвеер Baz(pow2(increment(x))).

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

Аналогично, если я придумаю, как переписать цикл в Вашем коде через рекурсию, не следует, что в Вашем коде рекурсия.

выделенным местом, куда можно что‑то положить и потом оттуда его брать

"Выделенным" означает, что у этого места есть (заданное в коде) имя.

var y = x * 10 + 5;

Вероятно, компилятор выделит место для хранения промежуточного результата вычислений (10*x), но это место не будет переменной, так как у него нет имени. Более того, разговор об этом лишён смысла без указания конкретных процессора и компилятора.

Например, если в процессоре нет инструкции Mul , то для хранения промежуточных результатов потребуется не одна, а несколько ячеек памяти (вычисление умножения через сложение). А если в процессоре есть инструкция AddMull, то промежуточных результатов вообще не будет.

Так какие ещё варианты написания кода без переменных?

Сначала нужно договориться о значении термина "переменная". В императивном программировании переменная - это именованная память.

Почему? потому что он более сложен к изложению чего-либо отличного от злосчастных никому не нужных рядов Фибоначчи.

Вы продолжаете повторять это необоснованное утверждение, игнорируя факты. Например, то, что моя программа на F# оказалась проще и короче, чем Ваша на php/perl.

«Отсутствие переменных» — это от Вашего непонимания, как оно работает под капотом.

Я прекрасно понимаю, как это работает под капотом. Но мы говорим о языках программирования, а не об архитектуре процессора. С таким же успехом можно заявить, что в ООП нет классов, так как в архитектуре процессора нет инструкции "создать экземпляр класса".

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

параметр return() — это тоже неявная [регистровая] переменная

параметр функции — это [регистровая] переменная, просто она не объявляется явно

Это неверно. Либо Вы вкладываете в термин "переменная" нетрадиционный смысл.

так отсутствие переменных возможно только при трансляции данных через каскады функций

Отсутствие переменных возможно в любой чистой функции.

int Baz(int x)
{
	var y = x + 1;
	return y*y;
}

Этот код можно переписать без объявления переменной:

int Baz(int x)
{
	int f (int y) => y*y;
	return f(x + 1);
}

даже в лиспе без переменных не обошлись

В лиспе есть "настоящие" переменные (defvar) и синтаксический сахар (let). Любую let переменную можно заменить на вызов функции.

после появления процедурного голанг

Go мультипарадигменный, а не «процедурный». Позволяет использовать ООП и ФП.

я в примере ни одной переменной не написал

Вы написали, что функциональный стиль - это цепочки функций. На самом деле это ортогональные понятия.

вызов функции стоит по накладным расходам

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

Information

Rating
Does not participate
Registered
Activity