LINUX.ORG.RU

Man or boy 2к25: Ваш статически типизированный ЯП полноценен?

 


0

4

Когда то Кнут придумал тест для ALGOL реализаций, и он известен под именем «Man or boy test». Но там просто локальные функции, не особо интересно.

Предоставляю вам версию для проверки языка программирования, на то, достоен ли он существовать в 21 веке!

Для начала нарушу это правило (у Python динамическая типизация), и покажу Python версию:

def print_sum(x):
  def make(acc):
    def f(y):
      print("acc(%d) + %d" % (acc, y))
      return make (acc + y)
    return f
  return make(x)

print_sum(10)(20)(30)(40)
Вывод
acc(10) + 20
acc(30) + 30
acc(60) + 40

Предлагаю попробовать повторить пример на вашем любимом статически типизированном языке, и поделиться им в комментариях.

Мое повторение на OCaml с rectypes:

let print_sum x =
  let rec f acc = fun y ->
    printf "acc(%d) + %d\n" acc y;
    f (acc + y)
  in 
  f x
  
let () = ignore (print_sum 10 20 30 40)
Типы он вывел сам, но можно и указать вручную:
type t = int -> t 

let print_sum (x : int) : t =
  let rec f (acc : int) : t = fun (y : int) : t ->
    printf "acc(%d) + %d\n" acc y;
    f (acc + y)
  in 
  f x
  
let () = ignore (print_sum 10 20 30 40)

Языки которые смогли реализовать тест на лямбдах/функциях, их система типов и ее записи позволяет строить рекурсивные по возврату лямбды и функции:

Языки у которых получилось, но замыкания были выраженны через структуры, потому что они так представленны в самом языке, это облегачает построение рекурсивных по возврату типов, потому что рекурсии в структурах есть везде:

Языки у которых пока не получилось без дополнительных средств типа классов/структур для обхода проблем с типами:

  • Rust (использование trait)
  • C (некорректная реализация)
  • Zig (использование классов)
  • D (использование делегатов)

Не являсь полностью статически типизированным языком, через свою систему типов смогли выразить пример

★★★★★

Последнее исправление: MOPKOBKA (всего исправлений: 21)
Ответ на: комментарий от monk

Вот это прям типичный пример непонимании концепции типов. Ты не можешь вместо 12 написать int и сказать что это тип. Ты потерял идентичность 12 и свёл её до убогой группы без свойств.

data IntT (n :: Natural) = IntT - здесь нет числа.

a = IntT :: IntT 4096 и здесь нет числа. В данном случае IntT :: IntT 4096 и IntT :: IntT 4095 не отличаются. Как и все остальные.

anonymous
()
Ответ на: комментарий от monk

Ещё один классический пример того почему здесь нет типов/вывода и в принципе ничего.

type family F a b where
  F Int Int  = Int
  F a Float = Float
  F Float a = Float
  F a b   = Float

Классическая таблица. Полное отсутствие типов, но типы то ладно - это сложно. Таблица никогда не работает.

Допустим, людям ставят задачу - напиши реализацию сложения. Примеры 2+2=4, 1+2=3. После этого идут и пишут это:

m[2][2] = 4;
m[1][2] = 3;

И она на полном серьёзе уверены что что-то сделали и что-то работает. Почему таблица не работает и не может работать я объяснял тысячи раз. В принципе достаточно сравнить эту страшную лапшу с нормальным языком. И проблема даже не в том что она страшная, убогая и тормозная. Таблица не может работать не по этому.

Тебе нужно описать все варианты рукой. И все эти варианты должны сводиться к одному поведению. К одному убого стёртому типу. Здесь нет типов. Здесь нет какого-то анализа аргументов. Нет никакого тайпчекинга вызова.

Людям максимально сложно это даётся. Предположим есть два явления с какими-то свойства и прочим. Мы всегда можем сказать «это первое, а это второе» и записать это на листочек. И у людей не хватает возможностей понять разницу между «записал явление» и «записал его номер».

У нас два варианта и таблица состоит из 4строк. Когда там будет 10 вариантов - можете посчитать количество строк. А потом добавится новая операция, которая потребует своей таблицы и так до бесконечности.

Именно поэтому ничего кроме лаб на палеолите не написано. И не будет написано никогда.

Самое смешное, что тут даже таблица не осилилась и она на самом деле не работает.

instance (Integral a) => Number Float a where add a b = add b a
instance (Integral a) => Number a Float where add a b = fromIntegral a + b

Тут убогий касты руками. Стирание даже не типов, а убогих фейковых типов. Пришлось стирать даже ту пародию что есть. О том что это рантайм-лапша даже говорить не приходится.

Люди постоянно пытаются натянуть задачу на свой ограниченный палеолит. Наделять условия задачи свойствами теми, что там нет. Ограничениями теми что там нет.

anonymous
()
Ответ на: комментарий от MOPKOBKA

Тебе нужно осознать то, что когда ты пишешь «можно ли» они не понимают ничего. Они не понимают ни что такое тип ни что там в принципе написано.

Я выше тебе писал, что числа там просто потому что ими удобно генерировать варианты. И да - они не понимают что такое числа. Он тебе родит int x и скажет «в него можно записать 40». Он видит int N и ему кажется что это какой-то инт. Нет. Собственно оно так и вышло.

Дак вот вставленные здесь «числа» это не числа, а то как будто бы ты руками написал struct i40; struct i25;. Это полностью отдельные типы.

Аналогично как и их операции. Мы их используем чтобы сгенерировать базу с которой мы работаем, а не потому что это числа.

anonymous
()
Ответ на: комментарий от MOPKOBKA

https://gcc.godbolt.org/z/bT59x6P95 - вот то, что нужно сделать. Просто мне лень генерировать это и я использую для этого числа. Но вопрос не в числах. Про числа вообще нельзя говорить - они не понимают что это такое.

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

Допустим, когда мы говорим «это целое число» мы не теряем информацию о том что это за число. У них совершенно иные шизо-представления. Для них если 10 сводится к инту и 20 сводятся к инту, то это инты. Здесь нет логики - здесь есть шизофрения.

anonymous
()
Ответ на: комментарий от anonymous

В данном случае IntT :: IntT 4096 и IntT :: IntT 4095 не отличаются.

А в чем отличие между template <int N> struct int_t{};? Как разные типы, Haskell их различает, и вместо IntT 100 нельзя передать просто 100.

a = IntT :: IntT 100
b = IntT :: IntT 200

hello_100 :: IntT 100 -> IO ()
hello_100 x =
  putStrLn "Hello World"  
  
main = do
  hello_100 a
  -- Ошибка: hello_100 100 
  -- Ошибка: hello_100 b

MOPKOBKA ★★★★★
() автор топика
Ответ на: комментарий от anonymous

data IntT (n :: Natural) = IntT - здесь нет числа.

также как и в

template <int N> struct int_t {};

В данном случае IntT :: IntT 4096 и IntT :: IntT 4095 не отличаются.

Отличаются

{-# LANGUAGE DataKinds #-}
import GHC.TypeLits

data IntT (n :: Natural) = IntT

a = IntT :: IntT 4096

f :: (IntT 4095) -> Int
f x = 5
ghci> f a

<interactive>:1:3: error: [GHC-83865]
    • Couldn't match type ‘4096’ with ‘4095’
      Expected: IntT 4095
        Actual: IntT 4096
    • In the first argument of ‘f’, namely ‘a’
      In the expression: f a
      In an equation for ‘it’: it = f a
monk ★★★★★
()
Ответ на: комментарий от anonymous

Тут убогий касты руками. Стирание даже не типов, а убогих фейковых типов. Пришлось стирать даже ту пародию что есть. О том что это рантайм-лапша даже говорить не приходится.

Какие касты? Здесь определение функции для любого типа из класса типов Integral.

И в рантайме никаких проверок, разумеется нет.

У нас два варианта и таблица состоит из 4строк. Когда там будет 10 вариантов - можете посчитать количество строк. А потом добавится новая операция, которая потребует своей таблицы и так до бесконечности.

Так в постановке задачи было 4 разных действия. Если на каждую комбинацию из 10 типов будет уникальный алгоритм, то естественно все 100 уникальных алгоритмов должны быть где-то описаны.

monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Как разные типы, Haskell их различает

Нет. Ещё раз повторяю - вы не понимаете что такое типы и что такое «различает». Давай попроще.

Представь такой код на сишке, где у тебя будет int init(int x) { assert(x == 100); return x; } - позволяет ли это различать? Нет, не позволяет.

и вместо IntT 100 нельзя передать просто 100.

Осознай как это работает. Это убогая таблица, где ты руками нагадил вот это:

a = IntT :: IntT 100

Там в реализации нет никаких типов. Нет ничего. У тебя тип - это ничто. Всё что оно делает - это условных колхозным типом вытаскивает из твоей строчки литерал и сравнивает.

Это значит, что как только ты преобразуешь этот тип - строчка пропадёт и костыльный иф сломается.

Такая же ситуация как с таблицей. Ты можешь написать таблицу, но как только ты хочешь сделать композицию - ты не можешь ничего сделать. Ты можешь работать только с тем, что написал рукой. Что кастанул рукой.

anonymous
()
Ответ на: комментарий от monk

также как и в

Нет. Ты врёшь. Собственно пример выше - действуй.

Отличаются

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

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

anonymous
()
Ответ на: комментарий от monk

Какие касты? Здесь определение функции для любого типа из класса типов Integral.

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

И в рантайме никаких проверок, разумеется нет.

Разумеется есть.

Так в постановке задачи было 4 разных действия. Если на каждую комбинацию из 10 типов будет уникальный алгоритм, то естественно все 100 уникальных алгоритмов должны быть где-то описаны.

Нет никаких уникальных «алгоритмов» и прочих допотопных сказах в рамках попыток съехать в жаву. Ладно, я буду думать что ты действительно не понимаешь проблемы, а не просто навязываешь мне что-то.

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

Вот 1 + 2 - это два отдельных типа. Они вместе дают 3 - это другой тип. Неважно что там - важно то, что + - это полиморфная операция, которую ты пытался родить.

Только вот ты родил что-то типа |, который конечно же не работает, но в любом случае. Вот сделай следующий шаг - объедини одно и другое.

Понимаешь, да. Если мы создали 100 «алгоритмов», а потом их скомбинировали - это порождает ещё тысячи алгоритмов. Таких же уникальных. Но мы их не писали.

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

Это две базовые ошибки. Мыслить какими-то нелепыми интегралами, которые на самом деле один тип. Много не выражается через один. Никак. Аналогично с тем, что наличии таблицы что-то определяет. Если у меня есть таблица для каких-нибудь базовых примитивов - это не значит что у меня есть таблица для процессора, который из этих примитивов состоит.

Вы вообще как в этом мире живёте? Аналогично у тебя есть таблица умножения/сложения, но нет и не может быть таблицы для всех возможных их комбинаций. Задача не требует наличия таблиц - их требует твоё непонимание. Как ребёнок заучивший таблицу умножения думает, что в этом мире ограничено и работает через таблицу.

anonymous
()
Ответ на: комментарий от alysnix

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

Ведь он же понимает, что когда в си есть инт - в реальности там не инт, а число. Определённое значение. И любая операция определяет результат для каждого отдельного числа и их комбинации. Нет вообще никаких интов и прочей этой банальной чуши.

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

Дак вот реальность определяет однозначность. Их шиза говорит «ну мы считаем что знаем - значит знаем». Очевидно, что это настолько поехавшая методичка. Но они в неё массово верят. В принципе сбацать лабу и этого хватит.

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

Представь, что тебе дают задачу - реализовать умножение. И ты начинаешь гнать пургу «ну любая чиселка это чиселка, а значит я могу вернуть любую чиселку и считать что умножение работает». Казалось бы это чушь, но они на полном серьёзе утверждают это.

anonymous
()
Ответ на: комментарий от anonymous

Дак вот вставленные здесь «числа» это не числа, а то как будто бы ты руками написал

Да, я понимаю, а в чем отличие от https://godbolt.org/z/Px67Ef5v8 ?

Это значит, что как только ты преобразуешь этот тип - строчка пропадёт и костыльный иф сломается.

Преобразую во что? Тут нужен какой то конкретный минимальный пример.

Почитал про эти DataKind, возможность вычислять на них есть, вот пример:

{-# LANGUAGE DataKinds #-}
import GHC.TypeLits
import Data.Proxy

data IntT (n :: Natural) = IntT 
add_t :: IntT x -> IntT y -> IntT (x+y)
add_t IntT IntT = IntT
value_of :: KnownNat n => IntT n -> Integer
value_of (int :: IntT n) = natVal (Proxy :: Proxy n)

-- Перегрузки функций нету, передаю через f_add 
expr f_add x y = f_add x y 

-- В обоих случаях = 300
result_type = expr add_t (IntT :: IntT 100) (IntT :: IntT 200)
result_value = expr (+) 100 200

main = do 
  putStrLn (show (value_of result_type))
  putStrLn (show result_value)

MOPKOBKA ★★★★★
() автор топика
Ответ на: комментарий от anonymous

https://gcc.godbolt.org/z/bT59x6P95 - вот то, что нужно сделать.

{-# LANGUAGE DataKinds, NoStarIsType #-}
import GHC.TypeLits

data IntT (n :: Natural) = IntT deriving (Show)

add :: (IntT a) -> (IntT b) -> (IntT (a + b))
add x y = IntT

mul :: (IntT a) -> (IntT b) -> (IntT (a * b))
mul x y = IntT

wexpr a b c  = add (mul (add (add a b) c) c) (mul b a)

i1 = IntT :: IntT 1
i2 = IntT :: IntT 2
i3 = IntT :: IntT 3

ghci> :type wexpr i1 i2 i3
wexpr i1 i2 i3 :: IntT 20
monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Давай ещё раз поясню, включая вопросы выше. Есть некие требуемые свойства, которые определяют явление. Допустим, понимание. Ты не можешь взять одно из свойств и говорить «это одно и тоже», либо «это оно и есть».

Любая допотопная чушь их 60 содержит в себе эту проблему. Ты всегда можешь сделать какой-то костыль, который где-то на 1% на одном из тысяч этапов воспроизведёт поведение. Но нам важно не то что происходит, а то почему оно. Ну как в базовой куллстори про часы и то что они неправильно показывают время иногда. Ты не должен мыслить в рамках этого «иногда». Тебя пытаются обмануть и запутать.

И выше я дал как раз таки критерий, как и изначально дал критерий. Вот представь что ты сделал тупую проверку, где проверка сводится к следующему - «я даю ошибку если выше в тексте нет подобного токена» - сработает ли его проверка? Да. Поэтому это не критерий. А примерно так оно и работает.

И как нам уйти от этого? Уйти от этих манипуляций? Нужно создать что-то, чего не будет в тексте. Ведь в этом и фишка. Как и фишка моих примеров для цпп - там ничего этого нет. Мы работаем на тех уровнях, где мы ничего заранее не описали.

Почему никто не может родить следующий шаг? Потому что на самом деле ты можешь написать IntT 100, но далее когда ты захочешь это объединить - ты объединишь это в IntT без ничего и оно перестанет работать. Поэтому важен следующий шаг.

Вон недавно кто-то из раст-шизов опять начал рассказывать сказки про «шаблоны - это макросы» и там такая же проблема. Все фокусы невежества основаны на этом фокусе. Ты можешь взять макросню и попытаться написать на ней add(x, y) и оно типа будет работать. Но работает оно по другой причине. Вспоминаем, что нам важна причина, а не поведение. Поведение это то что нам помогает понять причину.

Если они не могут этого осознать нам нужно пойти дальше. Заставить их сделать композицию, либо передать макрос в макрос. И всё они тут же сливаются. Потому что врать - это не разбираться. А ошибаться это не врать.

Задача вранья всегда изолировать какое-то одно свойство из множество и путём игнорирования и отрицания всего остального - показывать какие-то фокусы. Так нельзя делать.

anonymous
()
Ответ на: комментарий от anonymous

Потому что на самом деле ты можешь написать IntT 100, но далее когда ты захочешь это объединить - ты объединишь это в IntT без ничего и оно перестанет работать.

Вот тут непонятно, что именно нужно объединить так, что бы IntT потерял свой скаляр.

То что ты пишешь про макросы vs шаблоны мне понятно, я не вижу в этой ситуации с IntT где у него что то теряется и пропадает.

«Передать макрос в макрос» - вот хорошая проверка и доказательство того что макросы не такие мощные как шаблоны, что является хорошей проверкой для IntT?

MOPKOBKA ★★★★★
() автор топика
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от monk

Там есть какие-то Natural и какие-то числа? Нет. Не позорься.

Для тех кто не понял - он просто взял взял и написал int iexpr(int a, int b, int c) { return (a + b + c) * c + b * a; } - обыкновенную рантайм-баланду со стриранием типов.

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

anonymous
()
Ответ на: комментарий от anonymous

Потому что на самом деле ты можешь написать IntT 100, но далее когда ты захочешь это объединить - ты объединишь это в IntT без ничего и оно перестанет работать.

Как оно может быть без ничего, если есть обязательный числовой параметр.

Заставить их сделать композицию, либо передать макрос в макрос.

Так и шаблон нельзя передать параметром в функцию. Только результат раскрытия. И макрос аргументом макроса превосходно может быть.

monk ★★★★★
()
Ответ на: комментарий от anonymous

Для тех кто не понял - он просто взял взял и написал int iexpr(int a, int b, int c) { return (a + b + c) * c + b * a; } - обыкновенную рантайм-баланду со стриранием типов.

Кто «он»? Ты в годболте? Вычисление типа wexpr i1 i2 i3 как и любого другого типа происходит при компиляции.

monk ★★★★★
()
Ответ на: комментарий от monk

Ошибся в удаленном комментарии, спутал с iexpr веткой. У GHC очень неудобно читать выхлоп.

Литералы типов не замечены мной в выхлопе, есть только итоговый результат 600. Так что пока тоже стою на версии что все происходит в compile-time. А вот литеры для iexpr ветки в выхлопе есть.

https://godbolt.org/z/E135oGxPs

MOPKOBKA ★★★★★
() автор топика
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от MOPKOBKA

Преобразую во что? Тут нужен какой то конкретный минимальный пример.

Вот пример: n :: Natural

Откуда ты взял какой-то Natural и прочий мусор из жавы? Откуда ты взял какой-то show? Какие Proxy? Это всё мусор для дошкольников.

Почитал про эти DataKind, возможность вычислять на них есть, вот пример:

Никаких DataKind и прочего мусора у тебя быть не должно. Это ещё одна ваша проблема. У вас не получается получать базовое свойство - вы начинаете тащить всё больше и больше мусора. Что ещё больше вас запутывает.

Условно «я не смог сделать без таблицы» - «я пошёл взял какой-то костыль который имеет в себе захаркоженную таблицу/какие-то костыли для не столь позорной её генерации». Это не решение проблемы. Это не попытка понять проблемы. Это просто бесконечная генерация какая-то шизы.

anonymous
()
Ответ на: комментарий от monk

Вычисление типа wexpr i1 i2 i3 как и любого другого типа происходит при компиляции.

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

Ну и да, давай ссылку на годболт на свой мусор.

anonymous
()
Ответ на: комментарий от anonymous

Откуда ты взял какой-то Natural и прочий мусор из жавы?

Это вид типов, соответствующий целому числу. При чём тут жава? В неё вообще видов типов нет.

Условно «я не смог сделать без таблицы»

Так и ты не смог сделать без таблицы. Только в шаблоне-макросе и типов нет, а есть только подстановка текста при компиляции.

monk ★★★★★
()
Ответ на: комментарий от anonymous

Никакого типа нет никаких вычислений нет. Тебе сказали, что там нет никаких чисел и прочего твоего мусора. Ничего нет.

Солипсист-программист это сурово. Ладно, пусть ничего нет.

monk ★★★★★
()
Ответ на: комментарий от monk

Как оно может быть без ничего, если есть обязательный числовой параметр.

Там нет никаких «числовых» параметров. Если они есть это не тип.

Так и шаблон нельзя передать параметром в функцию.

Да ты чё. У тебя автору написали в первом же крестовом примере передачу шаблона. f([](auto) {}) - это передача шаблона, представляешь.

И макрос аргументом макроса превосходно может быть.

Там речь была про конкретный язык, а не про «могут», да и то как они могут видно. К тому же это бесполезно и мне лень объяснять почему. Для начала нужно хотя бы что такое типы осилить.

anonymous
()
Ответ на: комментарий от anonymous

у типа данных есть довольно строгие определения, и они не такие как у тебя.

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

это можно и нужно отлить в граните и поставить себе на стол, и посматривать перед обсуждением типов.

а то что вы тут понимаете под типами - собачьи какашки.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от monk

Это вид типов, соответствующий целому числу. При чём тут жава? В неё вообще видов типов нет.

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

Так и ты не смог сделать без таблицы.

Что значит не смог, если смог? Как раз таки в первом примере, где все эти типы генерируются как раз таки на основе базовой полиморфной операции.

Представляешь + это не мусор вида инт+инт как у тебя в скриптухе. Поэтому я могу каждый её выход преобразовать в тип, вернее обернуть. И вот у меня был 1, который я рукой обернул в i1, а потом операция мне сгенерировала всё остальное. Именно так как я сделал это руками.

Только в шаблоне-макросе и типов нет

Как это нет, если есть. В твоей макросне убогой нет, да. Но твоё невежество это не реальность, а твоя проблема.

а есть только подстановка текста при компиляции

Конечно же нет. И тебе дали критерий на котором ты поплыл - подстановка не может ничего создать. Собственно поэтому ты не смог, а шаблон смог. Аналогично нельзя подставить текст которой нет. Показывай текст, который был подставлен.

anonymous
()

Man or boy

в 21 веке

достоен ли он существовать

Если переименуют в «Glenn or Glenda», то - будет достоин. А сейчас его удал это «платить и каяться», хехехе

somemong
()
Ответ на: комментарий от MOPKOBKA

А можно ли написать add если вместо Natural будет Float к примеру?

Там числа Пеано внизу. Если сможешь Float и их суммирование через них выразить, то да.

Можно рациональным числом параметризовать (которое по факту натуральный числитель и знаменатель).

monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Ещё раз. Ты пользуешься неправильными критериями.

Так что пока тоже стою на версии что все происходит в compile-time.

Откуда ты взял какой-то compile-time? Тебе вбросили и ты повторил? Это так не работает. Типизация не имеет никакого отношения к кт.

Как только ты видишь:

Natural KnownNat Proxy и импорт прочего мусора - это сразу для тебя должно отменять потугу. Потому что по условию задачи никаких групп и прочего мусора нет. А типы в языке это базовая сущность, а не какой-то мусор.

Ну и если ты хочешь узнать что это действительно тип - ты подставляешь это тип туда, где этот тип может стоять. И да, в контексте где нельзя сделать убогую текстовую подстановку.

Допустим берёшь eq(T, T), потом берёшь foo(auto x, auto y) { eq(add(mul(x, x), x), y);} и делаешь foo(2, 7) - у тебя должен сломаться тайпчекинг.

Опять же важно отличать тайпчекинг от убого евала скриптухи. Допустим ты можешь параллельно с этим всем делать вычисления в рантайме. Конечно это тоже не гарантия, но как минимум усложнит им попытку наврать.

anonymous
()
Ответ на: комментарий от monk

Ну это получается действительно неполный аналог из C++, где параметр довольно свободен. Может принимать разные типы, не так ограничен в операциях итд.

MOPKOBKA ★★★★★
() автор топика
Последнее исправление: MOPKOBKA (всего исправлений: 2)
Ответ на: комментарий от anonymous

Допустим берёшь eq(T, T), потом берёшь foo(auto x, auto y) { eq(add(mul(x, x), x), y);} и делаешь foo(2, 7) - у тебя должен сломаться тайпчекинг.

eq :: a -> a -> a
eq x y = x

foo x y = eq (add (mul x x) x) y

xx = foo i2 (IntT :: IntT 7)
$ ghc typelit.hs
[1 of 2] Compiling Main             ( typelit.hs, typelit.o )

typelit.hs:23:14: error: [GHC-83865]
    • Couldn't match type ‘7’ with ‘6’
      Expected: IntT ((2 * 2) + 2)
        Actual: IntT 7
    • In the second argument of ‘foo’, namely ‘(IntT :: IntT 7)’
      In the expression: foo i2 (IntT :: IntT 7)
      In an equation for ‘xx’: xx = foo i2 (IntT :: IntT 7)
   |
23 | xx = foo i2 (IntT :: IntT 7)
   |              ^^^^^^^^^^^^^^

monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Ну это получается действительно неполный аналог из C++, где параметр довольно свободен. Может принимать разные типы, не так ограничен в операциях итд.

Потому что не типизирован. Там простая подстановка текста. И, разумеется, в текст можно воткнуть любое constexpr выражение.

Можно соорудить аналог на Template Haskell при желании. Он даже лучше: при компиляции произвольные действия позволяет как лисп.

monk ★★★★★
()
Ответ на: комментарий от alysnix

Клоун, я понимаю что ты нейробот, но всё же. Тут даже проблема не в том что это определение чушь и никого в реальности не волнуют определения для домохозяек. А то, что ты как и в прошлый раз опозорился даже в рамках того что копипастишь.

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

К тому же никакой строгости в определении нет. Потому что никаких значений нет. Какое значение у struct {}? Значит получается это не тип?

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

anonymous
()
Ответ на: комментарий от monk

Потому что не типизирован. Там простая подстановка текста.

Так параметр может иметь тип, вот например выдает ошибку при попытке передать строку:

template <int N> struct int_t {};
int_t<"stroka"> x;
Какая тут проблема с типизацией?

MOPKOBKA ★★★★★
() автор топика
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

Ты думаешь он что-то знает про цпп и тему? Его выше дали тезисы опровергающие его враньё(кстати он даже не привёл никаких оснований для набросов про «текста» ведь текст это именно у него). Это, кстати, обычная защита ботов - обвиняй другого в том, что делаешь сам.

Самое смешное, что он в этом опозорился потому как раз таки шаблоны не являются полиморфными в полной мере, потому что делались давно отчасти по допотопным методичкам. Правда вся база там иная, но подобные ограничения остались. Но они чисто легаси.

Аналогично там нет никакого constexpr - он не знает что это такое. И здесь он опять врёт, ведь убогий евал именно у него и он тебе его и показывает.

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

И да, int в шаблонах это не тип - это класс. Ну примерно тоже самое, что тогда модно было в палеозое. Ну вернее это номинально так, но в реальности оно иначе.

И поэтому он там нелепо позорится. Ему сказали что в шаблонах подстановка(на самом деле нет, но не по этой причине), но там есть его же методичка. Поэтому он теряется.

anonymous
()
Ответ на: комментарий от anonymous

Откуда ты взял какой-то compile-time?

Ты написал что Haskell wexpr == iexpr, я воспринял это как намек, на то что Haskell wexpr исполняется в RT. Твое пояснение с eq(T, T) ниже как будто тоже сводится к RT/CT, если все вычисления происходят в RT то несовместимость типов не может быть обнаружена, там будет какой нибудь 0..MAX int.

Тайпчекинг то что в CT, ты противопоставляешь это eval из скриптухи, а eval он обычно RT.

MOPKOBKA ★★★★★
() автор топика
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от MOPKOBKA

вот например выдает ошибку при попытке передать строку

В Template Haskell тоже выдаст при обработке параметра макроса.

Какая тут проблема с типизацией?

   template<auto y> auto operator*(int_t<y> v) const {
      return int_t<x * y>{};
    }

Напиши вместо auto типы для x и y. Их не существует. Они могут быть проверены только после текстовой подстановки по месту применения шаблона.

monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

А чего он позор свой спрятал с приколхоженным выше евалом и каким-то мусор вместо чисел?

Это тупой eval поверх жавы. Тут нет ничего из того что обсуждалось выше. Собственно то, что он делал выше и на что я уже отвечал.

Поэтому базовый критерий один - никаких общих типов. Это всегда подлог. Они когда давно когда делали свою поделку увидели у жавы интерфейс. Потом увидели, что поверх него можно сделать евал.

Там тип один. Он не меняется и с ним ничего не сделать. Взяли struct Natural { virtual Natural & operator+(Natural &); }; - насували это везде, а просто запустили евал. Как и наворовал всякой лапши из лефтпадов.

Здесь нет типов. Нет никакого отдельного поведения. Заметь как он потерялся тогда, когда я дал таблицу. Именно потому чтобы впарить тебе установку - жава это про типы, но нет.

Аналогично вывод там работает именно с Natural, а все попытки писать матчи это просто рантайм-мусор такой же как в жаве.

anonymous
()
Ответ на: комментарий от monk

Там же значения, можно тип возврата описать сразу как в Haskell.

template<int y> 
int_t<x*y> operator*(int_t<y> v) const 
{
  return {};
}

В Haskell для умножения ты тоже не пишешь конкретные числа, а указываешь Natural.

MOPKOBKA ★★★★★
() автор топика
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от monk

В Template Haskell тоже выдаст при обработке параметра макроса.

Нет, очевидно.

Напиши вместо auto типы для x и y. Их не существует. Они могут быть проверены только после текстовой подстановки по месту применения шаблона.

А вот ты можешь увидел то почему это типичный фанатик и почему врать и воровать для него смысл жизни.

Почему вот это foo x y = eq (add (mul x x) x) y не проверяется до «текстовой подстановки» по месту? Почему он себе такой вопрос не задаёт?

А знаешь почему? Потому что это рядовой бот, который повторяет самые убогие лозунги. Если бы он был не ботом - он бы понял, что его евал тоже ничего не проверяет. Значит он потерял свойство своей системы типов.

И в этом фишка. Поэтому они тащат весь мусор. Врут и прочее. Он когда воровал евал забыл, что он переопределил свойство из методички и теперь нельзя что-то проверить заранее. И потом мы видим такой нелепый позор.

Кстати, как он и продолжает нести чушь про какую-то текстовую подстановку, которой нет и он никогда не покажет где она и есть и где её свойства.

Кстати, этот клоун ещё пошёл гуглить про template<auto y> и пытаться подбивать это под методичку, хотя выше уже была дана информации, что там именно что проверяются типы. Вернее классы типов. Потому что там нет никаких его типов.

Что там за типы и куда их не существует. Не существует того что есть в жаве? Да. Так же как у тебя. Здесь нет подтипов, которые почему-то клоуны называют типами.

anonymous
()
Ответ на: комментарий от anonymous

Учитывая что там числа Пеано, сравнивать не имеет особого смысла с int_t из плюсов.

Но представим, что там нету ограничений по типам и операциям. Ты пишешь что все на интерфейсе Natural, но int это тоже интерфейс, разве нет? В чем разница между Natural и int?

То что оно не генерирует отдельные struct IntT10 / IntT20, похоже больше на вопрос кодогенерации, чем на то, с чем может взаимодействовать программист.

Абстракция в примере с eq не протекает. Пусть там отдельный шаг на eval идет. Как абстракция может протечь в итоге?

MOPKOBKA ★★★★★
() автор топика
Последнее исправление: MOPKOBKA (всего исправлений: 1)
Ответ на: комментарий от anonymous

Почему вот это foo x y = eq (add (mul x x) x) y не проверяется до «текстовой подстановки» по месту? Почему он себе такой вопрос не задаёт?

Проверяется

ghci> :type foo
foo :: IntT b -> IntT ((b * b) + b) -> IntT ((b * b) + b)
monk ★★★★★
()
Ответ на: комментарий от MOPKOBKA

Нет, он опозорился. Я же не зря писал о том что тут int это совершенно иное.

Давай ещё раз объясню. Шаблоны изначально были задизайнены по той же методички, что потом делали его скриптуху. Это я писал. Но там это иная семантика.

В общем у шаблонов есть typename/template/value - это их типы, но они не полиморфны по ним. int это подкласс value. И да, здесь пытались сделать именно Natural. Ему про это в методичке не рассказил.

Но далее шаблоны работают чисто по полиморфной модели в рамках своих классов. Это вызывает у него проблемы и уходя в отрицания в рамках истерики набрасывает «там нет», «там не проверяется». В этом его проблема.

В принципе ты там можешь написать и 1, но в качестве классов используются базовый сишные типы. Это не вопрос шаблона.

Это как выше, когда он опозоирлся с набросами про «нельзя передать шаблон». В том и смысл что можно и поэтому в цпп int_t<x> работает. Это именно что разрешение проблемы.

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

Аналогично мы не можем передать туда шаблон напрямую(что он судорожно пытался гуглить), но «не можем напрямую» не значит не можем. В это данность. Что в цпп когда-то нагадили жавой. Для совместимости её не поменять, но язык вырос из этих ограничений. Ещё в 80.

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

anonymous
()
Ответ на: комментарий от monk

Где ошибка до вызова? Тебе показали выше пример. Ты опять опозорился и пытаешься задним числом нагадить какую-то чушь нелепую? И да, любые набросы без кода умножаются на ноль.

anonymous
()
Ответ на: комментарий от MOPKOBKA

Абстракция в примере с eq не протекает. Пусть там отдельный шаг на eval идет. Как абстракция может протечь в итоге?

Вот этот foo из

foo x y = eq (add (mul x x) x) y

я могу поместить в переменную. Или даже в хэш.

То есть

foos = [foo, foo]

работает.

А вот С++ шаблоны в массив не сложить. Потому что у них нет типа.

monk ★★★★★
()