
Ilya
28.05.2018
18:20:36
сейчас попробую натянуть

Denis
28.05.2018
18:38:17

Ilya
28.05.2018
18:39:12
немного неправильно, в этом случае придется везде заворачивать по месту использования
я вообще пытаюсь сделать что бы у меня была монада пораждающая значения типа T

Google

Ilya
28.05.2018
18:39:47
и возможны всякие другие типы, которые тоже можно привести к типу Gen T
например локальная или глобальная переменная
собственно для этого и есть тайплкасс продьюсер
а заассайненый тайп OutType это типа оутпут продьюсера, но проблема что я не могу его задефайнить для непосредственно абстрактной монады с констрейнтом GenFunMonad, потому что тайпчекер отбрасывает этот контекст и спроведливо жалуется что инстанс для монадического кейса свлишком общий

Denis
28.05.2018
18:42:54

Ilya
28.05.2018
18:43:35
пользователи библиотеки будут страдать
дырявая абстракция получается
у меня так-то есть реализация без GenFunMonad где конкретная монада лежит и там всё это прекрасно работает
но проблема в том, что в этом случае не получится нормально заворачивать конкретную монаду в другие трансформеры
попробовал извратиться через фандепы, но уткнулся в то же самое место

Denis
28.05.2018
18:47:45
так, дальше код надо смотреть
я пальцем в небо попытался понять что хотите

Google

Ilya
28.05.2018
18:49:58
сценарий использования приблизительно такой
https://github.com/SPY/haskell-wasm/blob/master/src/Language/Wasm/Builder.hs#L807-L825

kana
28.05.2018
18:50:09
круто бы примеры упрощать до абстрактных, а то тут сходу кучу ненужной информации, вместо понимания проблемы я читаю именя типов чтобы понять что это

Ilya
28.05.2018
18:50:30
да, я пытался вначале ?
попробую абстракнее сформулировать

kana
28.05.2018
18:51:53
ну как я понял

Denis
28.05.2018
18:52:03
где-то было у меня такое недавно

kana
28.05.2018
18:52:04
нужен инстанс семейств от констрейтов инстансов

Ilya
28.05.2018
18:52:59

Denis
28.05.2018
18:55:33
@lonokhov У тебя вроде вот с сервантом такая же шляпа была как человек спрашивает. Не могу вспомнить точное решение, но смутно помню, что там нужно чтобы правая часть была разная в разных ассоциированных TF. Не напомнишь?
https://gist.github.com/SPY/ff745898629800f967949cd14ead1ed5
Ilya у @lonokhov было такое недавно, можно как-то переписать чтобы все работало

Dmitry
28.05.2018
18:58:08
А мое предложение не устраивает?

Denis
28.05.2018
18:59:08
если мне память не изменяет, то правые части в TF разные должны быть
сходу я бы предложить попробовать с Tagged вместо Proxy, чтобы их дифференцировать, но возможно я фигню говорю

Leonid
28.05.2018
18:59:55
Тут в обоих случаях Proxy t выходит. У меня выходило разное

Dmitry
28.05.2018
19:00:23
"правые части в TF разные" - я не понимаю, что ты имеешь в виду. Можно пример, чего нельзя?

Denis
28.05.2018
19:00:34
впрочем, если работает уже, то почему бы и нет?

Dmitry
28.05.2018
19:01:02
насчет "работает" - не факт ;-)

Google

kana
28.05.2018
19:01:05
про правые части - это уже какая-то инъективность

Ilya
28.05.2018
19:03:27
дочь периодически заставлять отвлекаться от хаскеля ?

kana
28.05.2018
19:03:55
фандепы в данной ситуации будут иметь те же проблемы, что и семейства

Ilya
28.05.2018
19:04:37

Denis
28.05.2018
19:07:07

kana
28.05.2018
19:07:30
{-# 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
вот уменьшенный пример

Denis
28.05.2018
19:08:19
это же Proxy
data Wrapper a = Wrapper

kana
28.05.2018
19:08:30
{-# 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
и вот он на фандепах
{-# 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
28.05.2018
19:10:59
что бы совсем ближе надо из враппера1 доставать враппер2
и из m (Wrapper1 t) тоже доставать Wrapper2 t
в этом случае как раз GHC резонно начинается ругаться что инстанс для монады полностью оверлапит инстанс для узкого кейса
потому что у Wrapper1 и (Monad m => m) одинаковые кайнды, как и у внутренних t и (Proxy t)

Denis
28.05.2018
19:14:09
чего-то я выше недопонял задачу и нагнал люто
дополнительный параметр как Дмитрий предложил должен помочь

Ilya
28.05.2018
20:06:56
похоже что работает, сейчас попробую расскоментировать и подправить основной кодбейз и посмотрим не вылезут ли какие-то краевые кейсы при интеграции с другими хаками

Google

Ilya
28.05.2018
20:29:12
вот компилирующийся сжатый экзампл
https://gist.github.com/SPY/dc5e70d1bb4de813446c1dd3391b61ae#file-overlapedmulti-hs
вроде разобрался почему он работает(сначала не очевидно было)

Dmitry
28.05.2018
20:33:39
TF IsLoc можно не делать на последних GHC. Использовать (==)
import Data.Type.Equality
...... ProducerB (Loc == m) m (m a))

Ilya
28.05.2018
20:35:02
последние это от 8.4?

Dmitry
28.05.2018
20:35:40
8.2 точно работает

Ilya
28.05.2018
20:36:30
ага, но у меня там энивей не 2 инстанса, а 3. Так что придется ввести вспомогательный енум
но в целом работает
Dmitry спасибо

Dmitry
28.05.2018
20:37:26
не нравится ... m (m a) ... как-то на ... m a ... хорошо бы параметры переделать

Ilya
28.05.2018
20:39:11
ну оно только для одного инстанса так криво
для других весьма логично
типа Loc t является продьюсером в монаде m
без этого указания потом гхц погрязнет в амбигуити
Dmitry нет, я всё-таки не до конца догоняю почему оно работает. Потому что IsLoc иньективна и на этом GHC успокаивается?

Dmitry
28.05.2018
21:28:34
хм..., а мне непонятно, что непонятно?
IsLoc, конечно, не инъективна. Почти всегда False дает. Инъективность не при чем

Ilya
28.05.2018
21:33:56
в итоге после интеграции в модуль по месту использования валятся ошибки вида
/haskell-wasm/src/Language/Wasm/Builder.hs:264:24: error:
• Couldn't match type ‘OutTypeHelp
(GetProdType (m34 (Proxy 'F32))) (m34 (Proxy 'F32))’
with ‘OutTypeHelp
(GetProdType (m32 (Proxy 'F32))) (m32 (Proxy 'F32))’
arising from a use of ‘sub’
я не уверен, что получится из этого вытянуть изолированный пример, но если кому-нибудь не лень позвать стэк для сборки, то могу закоммитить в веточку нерабочий код

Dmitry
28.05.2018
21:35:07
Была проблема, что Loc t и m (Proxy x) перекрывались. Так как в случае Loc (Proxy t) неясно какой инстанс использовать. Мы сказали, что, если Loc, то нужен инстанс для Loc, а не для m. (Это я телепатически догадался, а GHC не смог). Это мы явно передаем в первом параметре. Важно, что это не в констрейнте, а в нормальном параметре-типе.
А почему в одном месте m34?

Google

Dmitry
28.05.2018
21:36:00
т.е. в двух
почему они должны матчиться?
Если должны, напиши в сигнатуре констрейнт - в той функции, в которой вызываешь. Типа OutTypeHelp a ~ OutTypeHelp b

Ilya
28.05.2018
21:42:10
я покоментировал там лишнее что бы свести проблему к чему-то менее контекстнозависимому
есть например вот такая ошибка:
haskell-wasm/src/Language/Wasm/Builder.hs:875:19: error:
• Couldn't match type ‘OutType (Glob 'I32)’
with ‘OutType (Loc 'I32)’
arising from a use of ‘add’
NB: ‘OutType’ is a type function, and may not be injective
add :: (GenFunMonad m, Producer m a, Producer m b, OutType a ~ OutType b) => a -> b -> m (OutType a)
и вот само место вызова if' i32 ((heapNext `add` alignedSize) `lt_u` heapEnd)
OutTypeHelp a ~ OutTypeHelp b не так-то просто добавить, он уже 2 аргумента требует

Dmitry
28.05.2018
21:44:37
А чему реально OutType (Glob 'I32) и второй равны?

Ilya
28.05.2018
21:44:50
потому что оба Proxy 'I32
если интересно больше контекста - https://github.com/SPY/haskell-wasm/blob/refactoring/builder-monad/src/Language/Wasm/Builder.hs#L875

Dmitry
28.05.2018
21:46:47
Точно? Замени вызовы на undefined, загрузи ghci, сделай kind! OutType (Glob 'I32)
фух, может завтра гляну как-нибудь...

Ilya
28.05.2018
21:54:39
да, всё равно большое спасибо, у меня как минимум есть направление куда ковырять теперь
btw,
λ> :kind! OutType (Glob 'I32)
OutType (Glob 'I32) :: *
= OutType (Glob 'I32)
он почему-то не раскрывает эту тайпфункцию

Dmitry
29.05.2018
05:10:39
Посмотрел код. Я бы убрал ProducerType и лишний инстанс. Loc и Glob, похоже, одинаковые. Можно передавать Bool.
import Data.Type.Bool
.... m == Loc || m == Glob ...

Ilya
29.05.2018
05:58:31
Я не очень понимаю почему гхц не может раскрыть OutType