Вон в Си тожем можно указатель на функцию передать в качестве аргумента как параметр для другой функции. Но никто это не пиарит активно, что это якобы сверхкруто.
Здравствуйте, Эйнсток Файр, Вы писали:
ЭФ>В чём крутизна "функций высшего порядка"?
В замыкании контекста и в частичном применении.
ЭФ>Вон в Си тожем можно указатель на функцию передать в качестве аргумента как параметр для другой функции. Но никто это не пиарит активно, что это якобы сверхкруто.
Представь, у тебя есть функция f в Си, которая приминает указатель на функцию ℝ→ℝ. Ты можешь передать туда функцию sin или cos, например: f(sin) или f(cos). Но что если тебе надо передать туда функцию ℝ→ℝ, созданную из двухаргументной функции ℝ×ℝ→ℝ путём фиксации одного её параметра? Например, f( x ↦ atan2(1.0, x) ).
То же в отношении вернуть из функции функцию. Ты можешь из сишной функции вернуть указатель, но ты не можешь внутри этой функции динамически состряпать новую функцию подходящей сигнатуры, ты можешь только вернуть какую-то статически фиксированную функцию.
Здравствуйте, Эйнсток Файр, Вы писали:
ЭФ>Вон в Си тожем можно указатель на функцию передать в качестве аргумента как параметр для другой функции. Но никто это не пиарит активно, что это якобы сверхкруто.
В композиции и типизации. Например, в C есть офигенный функциональный qsort, который является функцией высшего порядка, т.к. в него передается компаратор. Но язык недостаточно выразителен, чтобы такие конструкции использовались массово для абстрагирования кода. Корявый синтаксис указателей на функции, void* вместо типа, отсутствие лямбд, что заставляет вызывающий код создавать отдельную функцию под компаратор.
Пример на тайпскрипте:
function sort<A>(array: A[], comparator: (a: A, b: A) => boolean) {
...
}
const myarray: string[] = []
function sortKey(s: string): string { ... }
sort(myarray, (a, b) => sortKey(a) < sortKey(b))
Здравствуйте, Эйнсток Файр, Вы писали:
ЭФ>Тогда я сделаю во всех функциях первый параметр void* и буду через этот параметр передавать контекст. ЭФ>А функции динамически не создаются, ведь они в коде программы все заранее написаны.
Любую программу можно написать на ассемблере и даже в машинных кодах. Зачем тогда Си?
Все это делается для большей выразительности, для исключения ошибок (чем больше компилятор может проверить — тем лучше; а void* это потеря информации о типе, компилятор там ничего не может проверить)
Нет такого преступления, на которое не пошло бы суверенное родоплеменное быдло ради продления своего бессмысленного рода и распространения своего бессмысленного генома.
Здравствуйте, Эйнсток Файр, Вы писали:
ЭФ>А функции динамически не создаются, ведь они в коде программы все заранее написаны.
Вполне можешь их динамически комбинировать. Например, есть набор функций (некоторые из которых игнорируют ненужный параметр или фиксируют недостающий из контекста, чтобы получить ℝ→ℝ):
Func<double, double>[] s_functions = new Func<double, double>[]
{
Math.Cos,
_ => DateTime.UtcNow.TimeOfDay.TotalMilliseconds,
x => Math.Atan2(DateTime.UtcNow.TimeOfDay.TotalSeconds, x)
};
Есть ФВП, которая как получает функции, так и возвращает:
Возвращает не значение скомбинированной функции в некоторой точке, а саму скомбинированную функцию. Значение для конкретного аргумента можно посчитать позже:
DateTime now = DateTime.UtcNow;
int count = s_functions.Length;
Func<double, double> g = s_functions[now.Day % count];
Func<double, double> h = s_functions[now.Hour % count];
Func<double, double> f = Combine(g, h);
Console.WriteLine(f(1729.0));
Попробуй сделать подобное на Си через указатели на функции ℝ→ℝ.
ЭФ>В чём крутизна "функций высшего порядка"? ЭФ>Вон в Си тожем можно указатель на функцию передать в качестве аргумента как параметр для другой функции. ЭФ>Тогда я сделаю во всех функциях первый параметр void* и буду через этот параметр передавать контекст.
В Си тоже можно динамический полиморфизм через ручные таблички виртуальных функций, в чём крутизна ООП...
Здравствуйте, Эйнсток Файр, Вы писали:
Q>>В Си тоже можно динамический полиморфизм через ручные таблички виртуальных функций, в чём крутизна ООП...
ЭФ>Gtk+ так и делает, и всё у них хорошо.
Поэтому можешь считать, что Си — это ООП язык с поддержкой ФВП. Я же не стремлюсь убедить лично тебя, просто привожу аргументацию в публичном обсуждении.
Здравствуйте, Qbit86, Вы писали:
Q>Например, есть набор функций (некоторые из которых игнорируют ненужный параметр или фиксируют недостающий из контекста, чтобы получить ℝ→ℝ): Q>Попробуй сделать подобное на Си через указатели на функции ℝ→ℝ.
"Func<double, double>" — это не "ℝ→ℝ". Это "double -> double".
Здравствуйте, Эйнсток Файр, Вы писали:
ЭФ>Вон в Си тожем можно указатель на функцию передать в качестве аргумента как параметр для другой функции. Но никто это не пиарит активно, что это якобы сверхкруто.
Здравствуйте, Эйнсток Файр, Вы писали:
ЭФ>Вон в Си тожем можно указатель на функцию передать в качестве аргумента как параметр для другой функции. Но никто это не пиарит активно, что это якобы сверхкруто.
Все изобретенные парадигмы программирования есть управление сложностью определенных аспектов решения.
В данном случае мы
1. конструируем функцию — параметризуем некий шаблон внешними зависимостями. При этом шаблон — это функция, параметр — снова функция.
2. абстрагируемся от этих подробностей, то есть, концентрируемся на важном с нашей точки зрения
Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, gandjustas, Вы писали:
G>>Как сделать на C вот это: http://blog.gandjustas.ru/2011/11/21/blog-post/ ?
G>>Круто это когда язык позволяет такое писать.
ARK>Это нечитаемый говнокод и круто, когда язык не позволяет такое писать.
Проблема в том, что все альтернативы "нечитаемому говнокоду" оказываются еще более нечитаемым говнокодом.
Здравствуйте, gandjustas, Вы писали:
G>>>Как сделать на C вот это: http://blog.gandjustas.ru/2011/11/21/blog-post/ ?
G>>>Круто это когда язык позволяет такое писать.
ARK>>Это нечитаемый говнокод и круто, когда язык не позволяет такое писать. G>Проблема в том, что все альтернативы "нечитаемому говнокоду" оказываются еще более нечитаемым говнокодом.
Ну хз. Как по мне, вот это
void fact{int x)
{
if (x > 1)
return x * fact(x - 1);
else
return 1;
}
гораздо читаемее, чем это
var fact = Y<int>(f => x => x > 1 ? x * f(x - 1) : 1);
Здравствуйте, Эйнсток Файр, Вы писали:
ЭФ>Вон в Си тожем можно указатель на функцию передать в качестве аргумента как параметр для другой функции. Но никто это не пиарит активно, что это якобы сверхкруто.
В C это неудобно. Но да, это тоже функция высшего порядка. А в чём тут пиар? Просто одна их техник функционального программирования.
Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, gandjustas, Вы писали:
G>>>>Как сделать на C вот это: http://blog.gandjustas.ru/2011/11/21/blog-post/ ?
G>>>>Круто это когда язык позволяет такое писать.
ARK>>>Это нечитаемый говнокод и круто, когда язык не позволяет такое писать. G>>Проблема в том, что все альтернативы "нечитаемому говнокоду" оказываются еще более нечитаемым говнокодом.
ARK>Ну хз. Как по мне, вот это
ARK>
Здравствуйте, gandjustas, Вы писали:
G>Как ни удивительно, но сейчас можно писать даже так: G>
G>int fact{int x) => x > 1 ? x * fact(x - 1) : 1;
G>
Это гораздо лучше, чем первоначальный вариант с комбинаторами и вложенными функциями. Хотя я все равно написал бы в несколько строк.
G>Более того, такой способ написания коротких функций является рекомендуемым.
Без уточнения, что понимается под "короткой функцией", это довольно вредная рекомендация. Впрочем, чего еще ожидать от индусской компании.
G>А еще можно написать так: G>
G>static void Main(string[] args)
G>{
G> int fact (int x) => x > 1 ? x* fact(x - 1) : 1; //ОМГ Функция внутри функции, нечитаемый говнокод
G> Console.WriteLine(fact(5));
G>}
G>
Функция внутри функции — это не говнокод сам по себе. А вот упакованная в 1 квадратный сантиметр не самая простая логика — это говнокод, ящетаю.
G>Или создатели языка C# стремятся к повышению объема нечитаемого говнокода, или твоя оценка ситуации неверна.