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 ответов

7 просмотров

Это побочный эффект 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 нельзя.

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

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

А случайно нет ли в паскале штатной возможности передать указатель и количество туда где array of в качестве аргумента?
zamtmn
25
Anyone here suffers from unexplained aural migraines, who would be up for talking for a bit? Doesn't *have* to be aural, but I am not asking about headaches, I mean actual mi...
Martin Rys
58
Ну раз я пока тут, задам пару глупых вопросов. Зачем писать на ассемблере если компилятор довольно умный, а ассемблер много времени занимает? В каких прикладных задачах сейчас...
Максим Рябцев
20
Я тут за тем, чтобы задать вопрос, так как не знаю ассемблер, учу с/с++. Короче, насколько дорога операция перехода в функцию при ее вызове? Дело в том, что в с++ есть макросы...
Максим Рябцев
12
А какие чаты вообще в ходу? Auto aim? И что еше
do you think you're better off alone? А
13
Привет, нужен совет старших товарищей. Есть глобальная переменная var DefaultDataFolder:string; инициализируем DefaultDataFolder:='a:\_OUT\'; есть примитивная процедур...
Max Otto
14
hello friends. Do you know how can I learn getx? I have a software project that I should deliver it up to 5 weeks later and I need to learn firebase too. I will be thankfull
AmirHossein Razavi
15
Доброе время суток! у меня тут иноды закончились. и понял почему по сути кстит, я периодически очищаю постгрес и сентри контайнер: postgres=# DELETE FROM nodestore_node WHER...
Юсиф Насиров
9
Вопрос. Теоретический. Есть список команд. Команды отправляю в обработку некой функции, по очереди. Разные команды могут давать разные результаты после обработки. В зависимос...
Serjone
7
я не магистр хаскеля, но разве не может лейзи тип конвертнуться в не-лейзи запросив вычисление содержимого прям при инициализации?
deadgnom32 λ madao
100
Карта сайта