instance Boxed b v => Boxed (Box b) v where
unwrap (Box x) = unwrap x
instance (l ~ r) => Boxed l r where
unwrap x = x
А, то есть если b и v не совпадают (то есть когда мы находимся в середине цепочки вскрытия Box-ов), то будет использован первый инстанс (точнее, unwrap из первого инстанса), а когда l совпадает с r (то есть последнее, холостое вскрытие для конкретного 123), то будет использован второй инстанс. Правильно?
Здравствуйте, WolfHound, Вы писали:
WH>Интересно но не понятно почему работает. WH>Дело в том что второй инстенс подходит для для всех типов и как следствие должна быть неоднозначность.
Здравствуйте, lomeo, Вы писали:
L>То, чем ты занимаешься, называется "извращение". Присоединюсь, если ты не против
Интересно, а вот такое можно как-нибудь без функциональных зависимостей заставить работать?
class Funct a b c d where
f_map :: (a -> b) -> c -> d
instance (Functor m, Funct a b c d) => Funct a b (m c) (m d) where
f_map = fmap . f_map
instance (a ~ c, b ~ d) => Funct a b c d where
f_map = id
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, deniok, Вы писали:
V>Интересная фича, но сдается мне, она возможна только если компилятор "видит" как формировался вложенный Box.
Да, но Simon Peyton Jones, похоже, взялся за суперкомпиляцию. Так что, возможно, GHC вскоре будет "видеть" довольно далеко.
Здравствуйте, Аноним, Вы писали:
L>>А сейчас не работает? Можно пример?
А>Неа:
При явном указании типа работает. Если же явного указания нет, то мы ничего не сделаем. Тут такой прикол. Несмотря на ограничения инстанса GHC выбирает инстанс исходя только и исключительно из его заголовка — Fucnt a b c d или Funct a b (m c) (m d). Тут даже Overlapping(Incoherent)Instances не поможет. Я подумаю, что тут можно сделать, но, как мне кажется, лёгкого пути здесь нет.
Re[6]: Этюд Unbox(Box<Box<...Box<T>...>> )
От:
Аноним
Дата:
05.07.10 14:29
Оценка:
Здравствуйте, lomeo, Вы писали:
L>Несмотря на ограничения инстанса GHC выбирает инстанс исходя только и исключительно из его заголовка — Fucnt a b c d или Funct a b (m c) (m d).
Что из заголовка, это понятно, но не понятно чем, в принципе отличаются:
instance (Functor m, Funct a b c d) => Funct a b (m c) (m d) where
f_map = fmap . f_map
и
instance Boxed b v => Boxed (Box b) v where
unwrap (Box x) = unwrap x
Почему для
f_map not [True]
выбирается, казалось бы, более общий случай
instance (a ~ c, b ~ d) => Funct a b c d where
а должен выбираться "more specific" (на мой взгляд — первый).
Здравствуйте, Аноним, Вы писали:
А>Что из заголовка, это понятно, но не понятно чем, в принципе отличаются: А>
А>instance (Functor m, Funct a b c d) => Funct a b (m c) (m d) where
А> f_map = fmap . f_map
А>
А>и А>
А>instance Boxed b v => Boxed (Box b) v where
А> unwrap (Box x) = unwrap x
А>
У меня же явный тип указан.
А>Почему для А>
А>f_map not [True]
А>
А>выбирается, казалось бы, более общий случай А>
А>instance (a ~ c, b ~ d) => Funct a b c d where
А>
А>а должен выбираться "more specific" (на мой взгляд — первый).
More specific выбирается по шапке. a b c d ничем не хуже в этом случае, чем a b (m c) (m d), т.к. kind на специфичность не влияют.
Re[8]: Этюд Unbox(Box<Box<...Box<T>...>> )
От:
Аноним
Дата:
06.07.10 07:32
Оценка:
Здравствуйте, lomeo, Вы писали:
L>У меня же явный тип указан.
Box b?
L>More specific выбирается по шапке. a b c d ничем не хуже в этом случае, чем a b (m c) (m d), т.к. kind на специфичность не влияют.
"a b c d" и "a b [c] [d]" тоже одинаково специфичны?
class Funct a b c d where
f_map :: (a -> b) -> c -> d
instance (Funct a b c d) => Funct a b [c] [d] where
f_map = map . f_map
instance (a ~ c, b ~ d) => Funct a b c d where
f_map = id
Здравствуйте, Аноним, Вы писали:
А>"a b c d" и "a b [c] [d]" тоже одинаково специфичны?
Хм, спасибо.. Видимо я себе неправильно представлял выбор инстанса, либо баг в GHC.
Re[10]: Этюд Unbox(Box<Box<...Box<T>...>> )
От:
Аноним
Дата:
06.07.10 18:02
Оценка:
Здравствуйте, lomeo, Вы писали:
L>Хм, спасибо.. Видимо я себе неправильно представлял выбор инстанса, либо баг в GHC.
Не думаю что баг. Просто не так все тривиально как кажется (во всяком случае для меня).
Кстати, можно еще ваш пример вот так переписать, для наглядности:
data Box a = Box a
class Unboxable m where
unbox :: m a -> a
instance Unboxable Box where
unbox (Box a) = a
instance Unboxable [] where
unbox [a] = a
class Boxed b v where
unwrap :: b -> v
instance (Unboxable m, Boxed b v) => Boxed (m b) v where
unwrap a = unwrap (unbox a)
instance (l ~ r) => Boxed l r where
unwrap x = x
*Main> unwrap (Box [Box [[5]]])
5
PS А изначально-то вопрос взялся в результате медитирования вот над этим олеговским примером: deepest functor
Подозреваю, что "не тот инстанс" выбирается не из-за того, что оба одинаково "специфичны" (иначе бы было бы "Duplicate instance declarations"), а потому что "нужный" инстанс слишком специфичен (m d). А вот функциональными зависимостями это кажется чинится..
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, lomeo, Вы писали:
L>>Хм, спасибо.. Видимо я себе неправильно представлял выбор инстанса, либо баг в GHC. А>Не думаю что баг. Просто не так все тривиально как кажется (во всяком случае для меня).
Suppose that from the RHS of f we get the constraint C Int [b]. But GHC does not commit to instance (C), because in a particular call of f, b might be instantiate to Int, in which case instance (D) would be more specific still. So GHC rejects the program. (If you add the flag -XIncoherentInstances, GHC will instead pick (C), without complaining about the problem of subsequent instantiations.)
Таким образом, если мы вместо OverlappingInstances используем IncoherentInstances, то GHC игнорирует следующую ошибку:
Overlapping instances for Funct Bool Bool [Bool] d
arising from a use of `f_map' at A.hs:12:14-29
Matching instances:
instance [overlap ok] (a ~ c, b ~ d) => Funct a b c d
-- Defined at A.hs:9:9-39instance [overlap ok] (Funct a b c d) => Funct a b [c] [d]
-- Defined at A.hs:6:9-44
(The choice depends on the instantiation of `d'
To pick the first instance above, use -XIncoherentInstances
when compiling the other instance declarations)
In the first argument of `print', namely `(f_map not [True])'
In the expression: print (f_map not [True])
In the definition of `main': main = print (f_map not [True])
Т.е. определить d надо явно для правильного выбора инстанса, потому что в одном случае (Bool) выберется один инстанс, как более специфичный, в другом ([Bool]) выберется другой. В моём случае с Boxed, видимо, мне просто повезло, что выбирался нужный инстанс — не знаю, тут надо подумать.