Aleksei (astynax)
И нельзя писать f :: Num a
Aleksei (astynax)
Но можно f :: Num a => a
Aleksei (astynax)
Классы, это как-бы свойства типа. И мы пишем не f :: Зелёноё, а f :: что-то (но что-то зелёное) :) Человек то умный, он может из первого вывести второе. А компилятор пока не готов к такому - ему нужно, чтобы был объект, пусть даже и со свойствами :)
Aleksei (astynax)
(ща набегут - как проснутся - и напишут, что я в корне неправ)
Нурлан
Нужно завести тонкую обёртку class Zp a where ... newtype Zpable a = Zpable a instance Zp (Zpable Int) where ... instance Num (Zpable a) where ...
мне нужно определить как дейсвуте класс Zp на Zpable и отдельно как действует класс Num на Zpable?
доня.
@newrlan на счёт ньютайпов, чтобы было немного понятнее, вот такой отвлечённый пример есть класс моноид и допустим те же целые числа являются одновременно моноидом и по сложению (с нейтральным нулём), и по умножению (с нейтральной единицей) но два инстанса Monoid для одного типа Int мы конечно сделать не можем но мы можем завести две обёртки: newtype IntAddMonoid = IntAddMonoid Int newtype IntMulMonoid = IntMulMonoid Int и написать разные реализации тайпкласса Monoid для них, и таким образом избежать того что инстансы будут пересекаться при этом так как это newtype а не data, никакого оверхеда в виде боксинга-анбоксинга в рантайме не будет (то есть в рантайме это будет просто Int, без всяких обёрток) + емнип там автодерайвятся всякие Coercible чтобы удобно было туда-сюда преобразовывать Int в IntAddMonoid/IntMulMonoid и обратно
Aleksei (astynax)
Да
Aleksei (astynax)
Нужно завести тонкую обёртку class Zp a where ... newtype Zpable a = Zpable a instance Zp (Zpable Int) where ... instance Num (Zpable a) where ...
Немного наврал в инстансе Num. Правильное объявление будет таким: instance Zp (Zpable a) => Num (Zpable a) where ... Тогда инстанс для Num нужен будет только один
Aleksei (astynax)
👍
Нурлан
@newrlan на счёт ньютайпов, чтобы было немного понятнее, вот такой отвлечённый пример есть класс моноид и допустим те же целые числа являются одновременно моноидом и по сложению (с нейтральным нулём), и по умножению (с нейтральной единицей) но два инстанса Monoid для одного типа Int мы конечно сделать не можем но мы можем завести две обёртки: newtype IntAddMonoid = IntAddMonoid Int newtype IntMulMonoid = IntMulMonoid Int и написать разные реализации тайпкласса Monoid для них, и таким образом избежать того что инстансы будут пересекаться при этом так как это newtype а не data, никакого оверхеда в виде боксинга-анбоксинга в рантайме не будет (то есть в рантайме это будет просто Int, без всяких обёрток) + емнип там автодерайвятся всякие Coercible чтобы удобно было туда-сюда преобразовывать Int в IntAddMonoid/IntMulMonoid и обратно
то есть по сути я могу в структуре прадлагаемой Aleksey (@astynax) использовать вообще Zpable Integer ?
Нурлан
теперь
Aleksei (astynax)
Да
Нурлан
и это не потребует затрат на лишнюю память?
Aleksei (astynax)
Нет :)
Нурлан
как на новую структуру данных?
Aleksei (astynax)
При компиляции newtype выкидывается. Т.е. никакого заворачивания/разворачивания не будет
Нурлан
Это круто!
Aleksei (astynax)
Нам тоже нравится :)
Нурлан
А можно еще один вопрос?
Aleksei (astynax)
Можно :)
Нурлан
я вот определил Num на Zpable, но я стремлюсь определить Fractional на Zpable
Нурлан
придется и на Num и на Fractional прописывать инстанс
Нурлан
или можно как-то это все в одну кучу собрать?
Alexander
нужно прописать инстансы для всех классов, может помочь расширение GeneralizedNewtypeDeriving
Alexander
GND работает так: разворачивает newtype, применяет инстанс базового типа и заворачивается обратно
Aleksei (astynax)
Num нельзя дерайвить, т.к. поведение зависит от инстанса Zp. Остальное можно, думается
Нурлан
вот теперь я хочу объявить тип пусть называется Zp61 как мне сказать что этот тип Zpable ?
Нурлан
я хочу прописать instance Zp Zp61 where
Нурлан
но я так понимаю, что мне нужно что бы Zp61 был типом Zpable (вот тут я уже поплыл)
Aleksei (astynax)
Не, Zpable нужет только для оборачивания существующих типов - Integer, Float, и т.п.
Aleksei (astynax)
Если есть кастомный тип, то для него инстансы можно писать, не оборачивая предварительно в Zpable
Нурлан
а как тогда написать instance Zp a => Num a ибо компилятор ругается
Aleksei (astynax)
А зачем такой инстанс писать то?
Aleksei (astynax)
Для Zp61 инстанс будет instance Num Zp61 where
Нурлан
ну у меня условно 100500 костомных типов, самое главное все они Zp
Нурлан
Для Zp61 инстанс будет instance Num Zp61 where
Я хотел как раз такого избежать
Нурлан
поэтому ввел Zp
Aleksei (astynax)
Тогда много конкретных инстансов instance Zp (Zpable Zp61) плюс один обобщённый instance Zp (Zpable a) => Num (Zpable a)
Aleksei (astynax)
И все значения заворачивать в Zpable (или использовать численные литералы)
Alexander
можно сделать newtype Zp (n::Nat) = Zp Int
Alexander
если 61 это модуль или что там из групп
Alexander
тогда написать инстанс для всего в соответствии с этим n
Alexander
и потом делать 1 :: Zp 35
Нурлан
и потом делать 1 :: Zp 35
прикольная возможность, а это конструкция Integer возьмет?
Нурлан
можно сделать newtype Zp (n::Nat) = Zp Int
в смысле сюда можно будет засунуть
Alexander
в n ?
Нурлан
да
Alexander
Nat ~ Integer но только положительные
Нурлан
можно сделать newtype Zp (n::Nat) = Zp Int
для меня это прям совсем что-то новое
Нурлан
я думал нельзя константы совать в объявления типов
Alexander
для отрицательных наверное надо будет Bool добавить чтобы вся машинерия работала
Alexander
в GHC.TypeLits есть кусок докумертации
Alexander
вообще это DataKinds + доп машинерия в ghc для того чтобы литералы можно было поднимать
Alexander
последнее для строк и натов есть
Alexander
но они не индуктивные будут
Alexander
для задачи наверное это и не нужно
Alexander
ghc пока ещё не идеально со всей этой машинерией работает, но если не нужно будет много вычислений на n то прокатит
Alexander
я к сожалению до ноутбука только к вечеру доберусь, так что полностью готовый пример со ссылками на релевантные статьи только вечером смогу сделать
Alexander
ну если на *тайплевел* термах будут всякие вычисления то там нужно очень следить за структурой чтобы доказать верность
Alexander
использование самих Zp не ограничивается
Alexander
просто если будет foo :: Zp n -> Zp m -> Zp (сложная формула от n m)
Alexander
то тайпчеккеру может плохо стать
Alexander
особенно если рядом будет другая сложная формула, которая сводится к тому же результату
Alexander
например доказать что Min n m = Min m n будет нетривиально
Alexander
есть пакет от кметта с аксиомами и плагин, но я схожу не помню
Alexander
в любом случае задачу это покрывать хорошо должно
Alexander
в модуле GHC.TypeLits есть всё для прыжков между type и value level
Cheese
есть какой-нибудь готовый тайпкласс или математический термин, обозначающий особое "пустое" значение? например, Nothing для Maybe точнее, мне надо обобщить Nothing и '\NUL' семантика — отсутствие значения
кана
наверное его можно назвать терминальным, но я не уверен а если его можно назвать еще и инициальным, то есть термин "нулевой"
Cheese
инициальный и терминальный подразумевает какое-то отношение, а у меня просто одно отдельное значение
Cheese
выколотое
Cheese
как non в линзах
Cheese
но Non, наверно, плохое название для класса
A64m
готовый класс в линзах и есть
A64m
но "пустое" значение оно не "выколотое" же, конструктор для него есть.