1. JavaScript / Говнокод #27991

    0

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    8. 8
    9. 9
    function fib<T>(n: T) {
        return n <= 2 ? n : fib(n - 1) + fib(n - 2);
    }
    
    function main()
    {
      print (fib(5));
      print (fib(6.0));
    }

    я вам принес "рекурсивные генерики"..... внимание вопрос... а каким таким хером получилось вычеслить тут возвращаемый тип, а ?

    Запостил: ASD_77, 04 Февраля 2022

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

    • а вот вам и дампик принес https://pastebin.com/0AeaRYrY
      Ответить
    • если бы вы знали какое это гов-но рекурсивные темплейты... просто ад
      Ответить
      • Блин, я сперва по твоему комменту подумал что типы рекурсивные.
        Ответить
        • > типы рекурсивные

          Возможно вы имели в виду индуктивные?
          Ответить
        • ты все проспал... рекурсивные типы уже были:
          type BadFlatArray<Arr, Depth extends number> = {
              obj: {
                  "done": Arr,
                  "recur": Arr extends ReadonlyArray<infer InnerArr>
                  ? BadFlatArray<InnerArr, [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20][Depth]>
                  : Arr
              }[Depth extends -1 ? "done" : "recur"]
          }["obj"];
          
          declare function flat<A, D extends number = 1>(
              arr: A,
              depth?: D
          ): BadFlatArray<A, D>[]
          
          function foo<T>(arr: T[], depth: number) {
              return flat(arr, depth);
          }
          
          function main() {
              foo<number>([1.0, 2.0], 2);
          }
          Ответить
    • > внимание вопрос... а каким таким хером получилось вычеслить тут возвращаемый тип, а ?

      В яжасцрипт только один численный тип, float64?
      Ответить
    • > а каким таким хером получилось вычеслить тут возвращаемый тип

      В момент инстанциации?
      Ответить
      • Там же рекурсия, как она инстанцируется?
        Ответить
        • Ну вот когда инстанциируется в fib(5), тогда и определится... В общем-то в крестах оно тоже прекрасно работает.
          Ответить
          • А как работает вот такой код?

            proc fib[T](n: T): T =
              return if n > 2: fib(n - 1) + fib(n - 2) else: n
            
            echo $fib[float](6.0)
            echo $fib[int](5)
            Ответить
            • Я не знаю как у ОПа реализовано, но скорее всего он инстанциирует на каждый простой тип.
              Ответить
              • То есть, если туда передать каку-нибудь обёртку IntegerJsonSerialisable, то всё попячится?
                Ответить
                • Ну там скорее всего будет один инстанс под Object или даже полный юнион со всей хуйнёй.
                  Ответить
                  • не будет.. тип определяется четко...
                    Ответить
                  • ответ.... у любой рекурсивной функции всегда есть конец.. как не крути. вот это конец всегда говорит какой тип возврата
                    Ответить
                    • T1 shit(T2 a)
                      {
                        return shit(a);
                      }
                      Ответить
                      • Ну или как-то так
                        template <typename T>
                        auto shit(T a)
                        {
                          return shit(a);
                        }


                        Рекурсивная функция вполне может "зациклиться".
                        То, что рекурсивная функция не зареркурсируется до бесконечности, еще надо доказать
                        Ответить
                        • а ты пробовал ее запускать?
                          Ответить
                          • А если тебе тип надо определить до запуска?
                            Ответить
                            • вот мне и надо определить тип до запуска...
                              Ответить
                          • Её не обязательно запускать, например пишешь:
                            auto f = shit<int>;
                            И получишь ошибку конпеляции
                            Ответить
                            • > ошибку конпеляции

                              Конпелятор подумает -- "бесконечная функция без побочек -- это UB, значит она не будет вызвана, значит можно выбрать любой тип, пусть будет void".
                              Ответить
                            • Кстати, вот тут
                              template <typename T1, typename T2>
                              T1 shit(T2 a)
                              {
                                return shit(a);
                              }
                              
                              auto f = shit<int, int>;
                              какая-то странная ошибка
                              error: no matching function for call to ‘shit(int&)’
                              Ответить
                              • > странная ошибка

                                Ниже конпелятор тебе поясняет эту ошибку: template argument deduction/substitution failed, couldn't deduce template parameter `T1'.

                                Т.е. он в момент конпеляции четвертой строчки искал какой-нибудь подходящий shit, но вариант с шаблоном не подошёл т.к. невозможно определить T1, а других вариантов и нету.
                                Ответить
                                • А, он пытался выяснить тип возвращаемого значения и просто перебирал возможные?
                                  Ответить
                                  • Он подбирал, во что скастить a?
                                    Ответить
                                    • Он подбирал какую из реализаций shit позвать.

                                      Но ты не указал T1 в строке 4 явно, а вывести его (по правилам крестов, когда вывод от аргументов к результатам) нельзя. Поэтому данный шаблон не подошёл. А других вариантов не нашлось.
                                      Ответить
                        • у этой функции хоть она и бесконечная всегда есть тип возврата т.е. 0 (int32)
                          template <typename T>
                          auto shit(T a)
                          {
                            if (a == 0) return 0;
                            return shit(a);
                          }
                          Ответить
                          • С тем же успехом она имеет тип int32 | "что угодно". Можно проверить: в первой строчке мы возвращаем 0, что соответствует. Во второй строчке она возвращает int32 | "что угодно", что тоже норм.

                            Да, это какой-то тип содержащий ноль, но почему int32? В принципе, подходит любой другой тип с нулём. И функция может вернуть что угодно при a != 0.
                            Ответить
                            • вернуть она не может что угодно ... есть только одно решение только при одном значении ... это если а = 0 то и результат = 0. если а != 0 т.е. значение неопределенно... (неопределенно - это не значит что угодно .. это значит мы не может определить т.к. процедура определения не имеет конца.
                              Ответить
                              • поэтому ответ всегда будет тип "int32". может ли когда либо shift изменить тип возвращаемого значения? нет не может. значит первый тип, который мы можем определить и есть тип возврата функции.
                                Ответить
                              • Ты уже второй раз за тред решаешь проблему останова. Астанавись!
                                Ответить
                                • Он ее решит, и получит нобелевскую премию, а вы будете посрамлены.

                                  Он и про P=NP докажет
                                  Ответить
                            • в коде возвращаемы тип всегда union { int32 v1, float v2 }; т.к. тип shit это всегда тип первого вернутого результата и тип shit ни при каких условиях не меняется

                              template <typename T>
                              auto shit(T a)
                              {
                                if (a == 0) return 0;
                                if (a == 1) return 1.0;
                                return shit(a);
                              }
                              Ответить
                              • > тип shit ни при каких условиях не меняется
                                В данном случае, возможно.

                                Но перепиши код как
                                template <typename T>
                                auto shit(T a)
                                {
                                  if (a == 0) return 0;
                                  if (a == 1) return 1.0;
                                  return shit(a - 1);
                                }

                                И, без обработки всего остального кода, тип возвращаемого значения в точности не узнаешь.
                                Ответить
                                • > в точности

                                  Тайпскрипт -- это не система доказательства теорем, сойдёт и более консервативный тип в духе int | float или даже any...
                                  Ответить
                                  • > сойдёт и более консервативный тип в духе int | float или даже any...

                                    ... и возвращаемое значение функции было разработано настолько, что туда помещался любой объект.

                                    Вообще в тайпскрипте скучно. Не то, что в крестах — перегрузка операторов, (частичная) специализация, ADL... Вопрос, что вызовется, может стать увлекательной головоломкой.
                                    Ответить
                                    • > что туда помещался любой объект

                                      Но с ним ничего нельзя было сделать, не вытащив обратно с помощью каста.
                                      Ответить
                                • не верно... аргумент "a - 1" не меняет ни тип результата "return 0", ни "return 1.0".. это значит что и при a и при (a-1) возвращаемый тип всегда один. это "(int | float)"
                                  Ответить
                                  • >аргумент "a - 1" не меняет ни тип результата
                                    В С++ есть перезгрузка операторов

                                    Яблоко минус int может быть груша
                                    Ответить
                                    • ну и что ... еще раз...поймите что код в функции shit который возвращает результат. это return и в независимости от кода в теле... типы возвращаемых данных не меняет
                                      Ответить
                                      • #include <iostream>
                                        
                                        template <typename T>
                                        auto shit(T a)
                                        {
                                          if (a == 0) return 0;
                                          if (a == 1) return 1.0;
                                          return shit(a - 1);
                                        }
                                        
                                        struct foo
                                        {};
                                        
                                        
                                        struct bar
                                        {
                                        //...
                                        //...
                                        
                                        int main()
                                        {
                                            std::cout << shit(bar{});
                                        }
                                        
                                        > Hi

                                        Предлагаю поработать нейронкой и дописать код, чтобы работало поведение.
                                        Ответить
                                      • А можно переписать эту фразу согласовав слова по правилам русского языка?
                                        Ответить
                                        • Он нейронка
                                          Ответить
                                        • там все просто.
                                          1) return shit(a - 1) какой имеет возвращаемый тип? случайный? - нет. он всегда предопределён. а что определяет возвращаемый тип функции shit? это строка "return 0" и строка "return 1.0". больше return в коде нет. значит список типов возвращаемых в shit - всегда предопределен и он конечен.
                                          Ответить
                                          • >- нет. он всегда предопределён
                                            к сожалению, нет. Он зависит от того, какого типа выражение "a - 1".

                                            Допустим, оно типа "яблоки".

                                            Но какого типа выражение "яблоки минус 1"?

                                            Допустим, оно типа "апельсины".

                                            Но какого типа выражение "апельсины минус один"?

                                            И так до бесконечности.

                                            Когда Алан Тюринг это понял, он обмокнул ножик в яде, разрезал яблоко, и съел половинку... и погиб:((((
                                            Ответить
                                            • Добавь к этому, что где-то ещё может быть
                                              template <>
                                              auto shit<апельсин>(апельсин a)
                                              {
                                                  return shit(a * a) + shit(a.съесть());
                                              }

                                              И всё становится просто прекрасно и легко вычисляемо.
                                              Ответить
                                              • Это явное инстанциирование шаблона для кейса "апельсин"?

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

                                                Кресты такие кресты
                                                Ответить
                                              • мы уже определили что данный код не компилируется.
                                                Ответить
                                            • я не вижу как а-1 делает возвращаемый тип "строка" или "гвоздь" у функции shit ... покажите мне в какой строке это происходит
                                              Ответить
                                              • Держи. Вызывается оригинальный shit и каким-то сраным образом возвращает строку. Удивительное рядом.
                                                #include <iostream>
                                                #include <typeinfo>
                                                
                                                template <typename T>
                                                auto shit(T a)
                                                {
                                                  std::cout << "Called shit with " << typeid(T).name() << '\n';
                                                  if constexpr (a == 0) return 0;
                                                  if constexpr (a == 1) return 1.0;
                                                  return shit(a - 1);
                                                }
                                                
                                                struct foo
                                                {};
                                                
                                                
                                                struct bar
                                                {
                                                    foo operator-(int)
                                                    {return foo{}; }
                                                    
                                                    bool constexpr operator==(int)
                                                    {return false;}
                                                
                                                };
                                                
                                                template<>
                                                auto shit<foo>(foo)
                                                { return "Hi"; }
                                                
                                                
                                                
                                                int main()
                                                {
                                                    std::cout << shit(bar{});
                                                }


                                                http://coliru.stacked-crooked.com/a/6f521a764aef91f5
                                                Ответить
                                                • ты тут изменил функцию shit при специализации ... и это уже не рекурсивный вызов. это вызов совсем другой функции
                                                  Ответить
                                                  • И шотландец вовсе не настоящий, ага.
                                                    Ответить
                                                    • а мой компилятор не позволяет говнять код... поэтому и результат прогнозируемый
                                                      Ответить
                                                    • я только сейчас понял какое - это гав-но ваш С++. это получается что любой левый может врубить свою специализацию на уровне сборки т.к. кто первый присоединился тот и герой и весь код пойдет по "пиз.де"
                                                      Ответить
                                                      • Ну поэтому не надо перегибать палку со специализациями...

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

                                                        > кто первый

                                                        Не, там всё сложнее. В каждой точке, где ты вызываешь функцию, составляется список вариантов, фильтруется, сортируется и выбирается "самый подходящий". Если выживет несколько кандидатов -- будет ошибка, а не первый.
                                                        Ответить
                                                        • на уровне линкера идет правило.. если я вижу func$xxx$1 (которые темплейт) из obj1 и точно такой же из obj2 то линькер возьмет первый и проигнорирует второй...
                                                          Ответить
                                                          • > на уровне линкера

                                                            Это другое, это нарушение ODR когда одноимённая функция в разных юнитах трансляции как-то получилась с разным телом.

                                                            А у разных специализаций имена разные, линкер их не мержит между собой.

                                                            З.Ы. Но если ты напишешь в джвух файлах разные специализации для одного типа -- вот там да, имена совпали, нарушение ODR, UB, кишки, распидорасило.
                                                            Ответить
                                                        • >просто неприятные различия в поведении.

                                                          Q: Почему одна и та же функция у меня в одном месте тормозит, а в другом летает?
                                                          A: Потому что нужно подключить petuh.hpp.

                                                          Реально ведь магия уровня Ruby: подключаешь файл, и всё начинает работать иначе
                                                          Ответить
                                            • еще раз... то что я съел не то же самое что я выкакал.. я всегда какаю говном .. без разницы что я съел
                                              Ответить
                                              • Как поспал, братишка? Проголодался наверное?
                                                Ответить
                              • Чем union отличается от onion?
                                Ответить
                      • C:\temp\MLIR_to_exe>clang++ -emit-llvm -O0 -c -S 1.cpp 1.cpp:7:10: error: function 'shit<int>' with deduced return type cannot be used before it is defined return shit(a); ^ 1.cpp:12:11: note: in instantiation of function template specialization 'shit<int>' requested here
                        Ответить
                        • Вообще, эта конструкция ужасна тем, что она может вернуть любой тип. Включая тот, у которого нет конструкторов. Именно поэтому в Coq её запретили.
                          Ответить
                    • > у любой рекурсивной функции всегда есть конец..

                      Наконец-то кто-то решил проблему остановки.
                      Ответить
                      • Концом он, видимо, называет ретурн.
                        Ответить
                        • При достаточно сложной системе типов от этого легче не становится: уже для type families вывод типов undecidable, емнип.
                          Ответить
                          • легко.. union { type1 t1, typ2 t2 } :) или (T1 | T2)
                            Ответить
                            • У тебя в ретурне может быть другая шаблонная функция с неизвестными типами.
                              Ответить
          • А такой?
            from typing import TypeVar
            
            T = TypeVar('T') 
            
            def fib(n: T) -> T:
                return fib(n - 1) + fib(n - 2) if (n > 2) else n
            Ответить

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