169 похожих чатов

{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE FlexibleInstances #-} module Smth where class Eq

a => X a

class Eq c => Y c

instance X a => Y a
Где то написано, почему такое не тайпчекается, то есть что надо instance (Eq a, X a) => Y a писать? Как то нелогично что ограничения на класс X игнорируются

11 ответов

16 просмотров

Это побочный эффект UndecidableInstances: поскольку мы отложили вычисление цепочки инстансов до рантайма, то и бонусов от него не получим. Если убрать необходимость в UndecidableInstances, то снова работает, например, module Smth where class Eq a => X a class Eq c => Y c instance X a => Y [a]

Anton-Sorokin Автор вопроса
Bodigrim🇺🇦
Это побочный эффект UndecidableInstances: поскольк...

Эм. До рантайма? Казалось бы, если например циклится - сразу говорит

Anton-Sorokin Автор вопроса
Bodigrim🇺🇦
Это побочный эффект UndecidableInstances: поскольк...

Но так то пример интересный, спасибо

Anton Sorokin
Эм. До рантайма? Казалось бы, если например циклит...

Как это говорит? В том-то и фишка UndecidableInstances, что компилятор не будет проверять тотальность и позволит писать штуки вроде {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} module Smth where class Eq a => X a class Eq c => Y c instance (Eq a, X a) => Y a instance (Eq a, Y a) => X a

кана
а, вот оно что

$p1X :: forall a. X a => Eq a $p1X = \(@a) ($x :: X a) -> case $x of $x { X eq _ -> eq } x :: forall a. X a => a x = \(@a) ($x :: X a) -> case $x of $x { X _ x -> x } $cp1Y_r1R2 :: forall a. X a => Eq [a] $cp1Y_r1R2 = \(@a) ($x :: X a) -> GHC.Classes.$fEq[] @a ($p1X @a $x) $cy_r1Q8 :: forall a. X a => [a] $cy_r1Q8 = \(@a) ($x :: X a) -> : @a (x @a $x) ([] @a) $fY[] :: forall a. X a => Y [a] $fY[] = \(@a) ($x :: X a) -> Y @[a] ($cp1Y_r1R2 @a $x) ($cy_r1Q8 @a $x) действительно, без undecidable он вытаскивает eq из x

Anton-Sorokin Автор вопроса
Bodigrim🇺🇦
Как это говорит? В том-то и фишка UndecidableInsta...

А, не говорит. Извиняюсь. Правда несуществующие инстансы и циклящиеся функции

Anton-Sorokin Автор вопроса
Bodigrim🇺🇦
Это побочный эффект UndecidableInstances: поскольк...

Главное, что добавление прагмы не ломает подобный (работающий без неё) код, в общем. На производительности кстати интересно как сказывается

Bodigrim🇺🇦
Это побочный эффект UndecidableInstances: поскольк...

Если верить нотам гхц (и если я их правильно понимаю) это все-таки так сделано чтобы избежать боттомов в суперклассах. Note [Recursive superclasses] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ See #3731, #4809, #5751, #5913, #6117, #6161, which all describe somewhat more complicated situations, but ones encountered in practice. See also tests tcrun020, tcrun021, tcrun033, and #11427. ----- THE PROBLEM -------- The problem is that it is all too easy to create a class whose superclass is bottom when it should not be. Consider the following (extreme) situation: class C a => D a where ... instance D [a] => D [a] where ... (dfunD) instance C [a] => C [a] where ... (dfunC) Although this looks wrong (assume D [a] to prove D [a]), it is only a more extreme case of what happens with recursive dictionaries, and it can, just about, make sense because the methods do some work before recursing. To implement the dfunD we must generate code for the superclass C [a], which we had better not get by superclass selection from the supplied argument: dfunD :: forall a. D [a] -> D [a] dfunD = \d::D [a] -> MkD (scsel d) .. Otherwise if we later encounter a situation where we have a [Wanted] dw::D [a] we might solve it thus: dw := dfunD dw Which is all fine except that now ** the superclass C is bottom **! The instance we want is: dfunD :: forall a. D [a] -> D [a] dfunD = \d::D [a] -> MkD (dfunC (scsel d)) ... ----- THE SOLUTION -------- The basic solution is simple: be very careful about using superclass selection to generate a superclass witness in a dictionary function definition. More precisely: Superclass Invariant: in every class dictionary, every superclass dictionary field is non-bottom To achieve the Superclass Invariant, in a dfun definition we can generate a guaranteed-non-bottom superclass witness from: (sc1) one of the dictionary arguments itself (all non-bottom) (sc2) an immediate superclass of a smaller dictionary (sc3) a call of a dfun (always returns a dictionary constructor) The tricky case is (sc2). We proceed by induction on the size of the (type of) the dictionary, defined by GHC.Tc.Validity.sizeTypes. Let's suppose we are building a dictionary of size 3, and suppose the Superclass Invariant holds of smaller dictionaries. Then if we have a smaller dictionary, its immediate superclasses will be non-bottom by induction. What does "we have a smaller dictionary" mean? It might be one of the arguments of the instance, or one of its superclasses. Here is an example, taken from CmmExpr: class Ord r => UserOfRegs r a where ... (i1) instance UserOfRegs r a => UserOfRegs r (Maybe a) where (i2) instance (Ord r, UserOfRegs r CmmReg) => UserOfRegs r CmmExpr where For (i1) we can get the (Ord r) superclass by selection from (UserOfRegs r a), since it is smaller than the thing we are building (UserOfRegs r (Maybe a). But for (i2) that isn't the case, so we must add an explicit, and perhaps surprising, (Ord r) argument to the instance declaration. TLDR: Вполне легально иметь осмысленный class A a class A a => B a instance A a => A a instance B a => B a Но в инстансе B гхц может захотеть достать из переданного B суперкласс A и получит боттом, вместо того чтобы взять fix instanceA и получить что-то осмысленное. В качестве фикса суперклассы можно доставать только из меньших по типу словарей, так что в instance X a => Y a использовать суперкласс X чтобы создать суперкласс Y нельзя.

Похожие вопросы

Обсуждают сегодня

Господа, а что сейчас вообще с рынком труда на делфи происходит? Какова ситуация?
Rꙮman Yankꙮvsky
29
А вообще, что может смущать в самой Julia - бы сказал, что нет единого стандартного подхода по многим моментам, поэтому многое выглядит как "хаки" и произвол. Короче говоря, с...
Viktor G.
2
30500 за редактор? )
Владимир
47
а через ESC-код ?
Alexey Kulakov
29
Чёт не понял, я ж правильной функцией воспользовался чтобы вывести отладочную информацию? но что-то она не ловится
notme
18
У меня есть функция где происходит это: write_bit(buffer, 1); write_bit(buffer, 0); write_bit(buffer, 1); write_bit(buffer, 1); write_bit(buffer, 1); w...
~
14
Добрый день! Скажите пожалуйста, а какие программы вы бы рекомендовали написать для того, чтобы научиться управлять памятью? Можно написать динамический массив, можно связный ...
Филипп
7
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
Ребят в СИ можно реализовать ООП?
Николай
33
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
Карта сайта