Кресты / Говнокод #24791 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
template <class F, class G>
auto operator*(F&& f, G&& g) -> decltype(auto) {
	return [=](auto ...args) { return f(g(args...)); };
}

Композиция функций

Запостил: IBets IBets, (Updated )

Комментарии (45) RSS

  • Хули:
    #include <stdio.h>
    
    int (*compose(int(*f)(), int(*g)()))() {
        int h(int x) { /* памагите много оргументов */
            return f(g(x));
        }
        return h;
    }
    
    int dbl(int x) {
        return x * 2;
    }
    
    int sqr(int x) {
        return x * x;
    }
    
    int main() {
    	printf("%d", compose(dbl, sqr)(5));
    	return 0;
    }

    Хули на идеоне не роботает?
    https://ideone.com/Ffcjmq
    Ответить
    • Потому что ссылаться на внутреннюю функцию снаружи — это царский метод. Функция compose возвращает указатель на трамплин, созданный в собственном стеке. После выхода из compose этот стек может повреждаться кем угодно. Ideone использует патч к компилятору типа propolice для обнаружения UB, который как раз ловит обращения к чужому стеку.
      Ответить
      • Чтобы это обойти, придётся писа́ть функцию compose, которая создаёт трамплин не в собственном стеке, а где-то ещё (в куче, но тогда после использования compose придётся кучу чистить вилкой, либо в стеке родительского контекста, в данном случае main), при этом придётся со страницы, в которой расположен трамплин, снимать защиту от исполнения кода, чтобы не сработал DEP. Будет гора некрасивого платформозависимого кода.
        Ответить
        • Ах! Какая грустная история! А в Форте я просто нопесал слово, который сконпелировал новую подпрограмму и всё. 🙂
          Ответить
    • В таком режиме даже трамплина не будет. Будет ссылка на внутреннюю функцию, которая захватит случайный аргумент из внешней функции.

      Надо компилировать с директивой {$modeswitch nestedprocvars}, тогда всё будет работать, в отличие от сишки:
      https://ideone.com/ZMFpW7

      Да, у указателя на функцию должен быть модификатор "is nested".
      Ответить
      • О! Крута! А могешь хуйнуть апиратор? А то у меня не получаиса:(
        Ответить
        • Фрипаскаль не хочет перегружать арифметические операторы для процедурных типов.

          Пытался задурить его с помощью class operator и дженериков, но что-то пока не получилось.
          Ответить
          • Подозреваю, что это ограничение ввели, чтобы не сломать операции с указателями. Нужно попытаться завернуть функции в классы.
            Ответить
            • Ну йопамать! Что же это за программирование, когда вместо того, чтобы просто что-то запрограммировать в удобном для себя виде, приходится мутить какую-то хуйню чтобы "обмануть" компилятор? Почему бы не позволить отключать все эти проверки по желанию?
              Ответить
        • Рано радовался. Пытался перекомпилировать у себя, не работает. Результат зависит от calling conventions и от состояния стека. Царский метод, короче.

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

          Искать решение задачи нужно в одном из двух направлений:
          1. Городить огород из асмовставок и всего такого.
          2. Оборачивать всё в классы и решать через ООП.

          В текущей версии fpc сделать проще вряд ли получится.
          Ответить
  • def compose( f, g ):
    	return lambda x: f( g( x ) )
    
    def f(x):
    	return x + 1
    
    def g(l):
    	return len( l )
    
    compose( f, g )([1,2,3])
    Ответить
      • Нет смысла переводить. Выше уже один гость написал реализацию композиции на "PHP". Ну хотя могу попробовать перевести и эту, если интересно.
        <?php
            function compose($f, $g) {
                return function() use($f, $g) { return $f(call_user_func_array($g, func_get_args())); };
            }
             
            $f = function($x) { return $x + 1; };
            $g = function($l) { return count($l); };
             
            echo compose($f, $g)([1,2,3]);


        https://ideone.com/gJG1aD

        Или так:

        https://ideone.com/YPq4FL
        Ответить
    • А теперь тоже самое, но f и g могут брать много аргументов.

      Можно, конечно,
      def compose2(f, g):
          return lambda *a, **kw: f(g(*a, **kw))
      но так только в g все аргументы передадутся, а f в пролёте.

      В отличие от хаскеля или даже C++, где компилятор типы проверяет, пользоваться этим говном можно только в примитивных случаях.
      Ответить
      • А вообще есть определение композиции функций нескольких аргументов?
        Ответить
      • Чому в пролёте? В пролёте только цивилизация кваргов:
        def compose2(f, g):
            return lambda *a, **kw: f(*g(*a, **kw))
        Ответить
        • > f(*g(*a, **kw))

          А теперь представим, что g возвращает список, и f принимает один аргумент — список.
          Ты всё сломал.
          Ответить
  • Эй, собака! Я засунул функцию в твою функцию, чтобы ты мог вызывать функцию, пока вызываешь функцию.
    Ответить

Добавить комментарий

Переведи на "PHP", guest!

    А не использовать ли нам bbcode?


    8