Ilya
начал переписывать тайпалиас на ньютайп + LibMonad тайпкласс и вылезла интересная проблема https://gist.github.com/SPY/ff745898629800f967949cd14ead1ed5
Ilya
раньше во вспомогательных тайпклассах я использовал конкретный тайпнейм и по этому тайпчекер всё понимал, но теперь когда всё ушло в констрейнты type OutType перестал чекаться, потому что для монадного инстанса он слишком общий
Ilya
это как-то можно победить? какой-нибудь волшебный экстеншен который позволит констренты в дефинишен типа например добавить или ещё что-то такое
Ilya
выглядит так, что мне нужно что-то типа этого https://ghc.haskell.org/trac/ghc/ticket/4259
Dmitry
m (Proxy t) перекрывается с Loc t. Надо как-то их разделять. У t кайнд Type в обоих случаях? Нельзя какой-нибудь специальный кайнд завести?
Dmitry
Можно еще добавить в класс параметр (isLoc :: Bool). И различать по 'True или 'False (скорее всего - вспомогательный класс сделать).
Alexander
Но мне кажется, что редактор одного языка не такая уж и плохая идея, вот idea изначально была такой
если редактор одного языка не может подсветить конфиги то се очень плохо
Alexander
хотя кому и Applicative конфиг
Ilya
Можно еще добавить в класс параметр (isLoc :: Bool). И различать по 'True или 'False (скорее всего - вспомогательный класс сделать).
это всё перекрывается тем, что GHC не чекает констрейнты, по этому даже вспомогательный класс если его запихнуть в констрейнты не поможет
Ilya
пытаюсь запилить на мультипарам тайпклассах, но пока что-то тяжко идет
Dmitry
Вспомогательный класс с доп. параметром с кайндом Bool.
Dmitry
А у тебя еще будут инстансы или только два? А то можно закрытую type family использовать. Там ничего не перекроется.
Ilya
я вынес в закрытую тайпфемили, но там всё ещё сложнее оказалось 🙂
Dmitry
Почему?
Ilya
там не очевидно что FunGenMonad m из констрейнта для produce мапится на FunGenMonad m из заголовка инстанса
Ilya
и получается что бы их унифицировать всё равно надо выносить это на уровень тайпкласса
Ilya
хотя загнался, это другая проблема
Ilya
ща вспомню почему не работала закрытая тайпфемили
Dmitry
Что-то такое должно работать наверное (не компилировал) https://gist.github.com/odr/44e6f17e3bc4616b2d055ceb2ee22a20
Ilya
сейчас попробую натянуть
Ilya
немного неправильно, в этом случае придется везде заворачивать по месту использования
Ilya
я вообще пытаюсь сделать что бы у меня была монада пораждающая значения типа T
Ilya
и возможны всякие другие типы, которые тоже можно привести к типу Gen T
Ilya
например локальная или глобальная переменная
Ilya
собственно для этого и есть тайплкасс продьюсер
Ilya
а заассайненый тайп OutType это типа оутпут продьюсера, но проблема что я не могу его задефайнить для непосредственно абстрактной монады с констрейнтом GenFunMonad, потому что тайпчекер отбрасывает этот контекст и спроведливо жалуется что инстанс для монадического кейса свлишком общий
Ilya
пользователи библиотеки будут страдать
Ilya
дырявая абстракция получается
Ilya
у меня так-то есть реализация без GenFunMonad где конкретная монада лежит и там всё это прекрасно работает
Ilya
но проблема в том, что в этом случае не получится нормально заворачивать конкретную монаду в другие трансформеры
Ilya
пользователи библиотеки будут страдать
я правда пока единственный пользователь библиотеки 🙂
Ilya
попробовал извратиться через фандепы, но уткнулся в то же самое место
Denis
так, дальше код надо смотреть
Denis
я пальцем в небо попытался понять что хотите
Ilya
сценарий использования приблизительно такой
Ilya
https://github.com/SPY/haskell-wasm/blob/master/src/Language/Wasm/Builder.hs#L807-L825
кана
круто бы примеры упрощать до абстрактных, а то тут сходу кучу ненужной информации, вместо понимания проблемы я читаю именя типов чтобы понять что это
Ilya
да, я пытался вначале 🙂
Ilya
попробую абстракнее сформулировать
кана
ну как я понял
Denis
где-то было у меня такое недавно
кана
нужен инстанс семейств от констрейтов инстансов
Denis
@lonokhov У тебя вроде вот с сервантом такая же шляпа была как человек спрашивает. Не могу вспомнить точное решение, но смутно помню, что там нужно чтобы правая часть была разная в разных ассоциированных TF. Не напомнишь?
Denis
https://gist.github.com/SPY/ff745898629800f967949cd14ead1ed5
Denis
Ilya у @lonokhov было такое недавно, можно как-то переписать чтобы все работало
Dmitry
А мое предложение не устраивает?
Denis
если мне память не изменяет, то правые части в TF разные должны быть
Denis
сходу я бы предложить попробовать с Tagged вместо Proxy, чтобы их дифференцировать, но возможно я фигню говорю
Denis
Leonid 🦇
Тут в обоих случаях Proxy t выходит. У меня выходило разное
Dmitry
"правые части в TF разные" - я не понимаю, что ты имеешь в виду. Можно пример, чего нельзя?
Denis
впрочем, если работает уже, то почему бы и нет?
Dmitry
насчет "работает" - не факт ;-)
кана
про правые части - это уже какая-то инъективность
Ilya
А мое предложение не устраивает?
я проверял фандепы. сейчас попробую ваш вариант.
Ilya
дочь периодически заставлять отвлекаться от хаскеля 🙂
кана
фандепы в данной ситуации будут иметь те же проблемы, что и семейства
Ilya
фандепы в данной ситуации будут иметь те же проблемы, что и семейства
да, я предполагал что так будет(эквивалентны же), но попробовать стоило
Ilya
сходу я бы предложить попробовать с Tagged вместо Proxy, чтобы их дифференцировать, но возможно я фигню говорю
я не могу разные правы части, мне как раз надо из разных типов один и тот же тип распаковывать по факту
кана
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} data Wrapper a = Wrapper class Class a where type ClassType a instance Class (Wrapper t) where type ClassType (Wrapper t) = t instance Monad m => Class (m (Wrapper t)) where type ClassType (m (Wrapper t)) = t вот уменьшенный пример
Зигохистоморфный
это же Proxy data Wrapper a = Wrapper
кана
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE MultiParamTypeClasses #-} data Wrapper a = Wrapper class Class a b | a -> b instance Class (Wrapper t) t instance Monad m => Class (m (Wrapper t)) t и вот он на фандепах
кана
это же Proxy data Wrapper a = Wrapper
да, я убрал лишний импорт, чтобы еще и инстанс монады у прокси убрать лишний
кана
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE MultiParamTypeClasses #-} data Wrapper1 a = Wrapper1 data Wrapper2 a = Wrapper2 class Class a b | a -> b instance Class (Wrapper1 t) t instance Monad m => Class (m (Wrapper2 t)) t взял разные обертки чтобы ближе к оригиналу
Ilya
что бы совсем ближе надо из враппера1 доставать враппер2
Ilya
и из m (Wrapper1 t) тоже доставать Wrapper2 t
Ilya
в этом случае как раз GHC резонно начинается ругаться что инстанс для монады полностью оверлапит инстанс для узкого кейса
Ilya
потому что у Wrapper1 и (Monad m => m) одинаковые кайнды, как и у внутренних t и (Proxy t)
Denis
чего-то я выше недопонял задачу и нагнал люто
Denis
дополнительный параметр как Дмитрий предложил должен помочь
Ilya
похоже что работает, сейчас попробую расскоментировать и подправить основной кодбейз и посмотрим не вылезут ли какие-то краевые кейсы при интеграции с другими хаками
Ilya
вот компилирующийся сжатый экзампл https://gist.github.com/SPY/dc5e70d1bb4de813446c1dd3391b61ae#file-overlapedmulti-hs
Ilya
вроде разобрался почему он работает(сначала не очевидно было)
Dmitry
TF IsLoc можно не делать на последних GHC. Использовать (==) import Data.Type.Equality ...... ProducerB (Loc == m) m (m a))
Ilya
последние это от 8.4?