Рискну предположить, что корень вашей проблемы в выражении with authSnaplet
.И вот почему:
∀x. x ⊢ :t with authSnaplet
with authSnaplet
:: AuthUser u => m b (AuthSnaplet b1 u) a -> m b v a
Не обращайте внимания на контекст, я заполнил несколько фиктивных экземпляров просто для загрузки материала в GHCi.Обратите внимание на тип переменных здесь - много двусмысленности, и, по крайней мере, две, которые, как я ожидаю, вы собираетесь иметь тот же тип.Самый простой способ справиться с этим, вероятно, создать небольшую вспомогательную функцию с сигнатурой типа, которая немного сужает, например:
withAuthSnaplet :: (AuthUser u)
=> Handler a (AuthSnaplet b u) (Either AuthFailure u)
-> Handler a s (Either AuthFailure u)
withAuthSnaplet = with authSnaplet
Опять, простите за глупость, у меня нет Snapустановлен в данный момент, что делает вещи неловкими.Введение этой функции и использование ее вместо with authSnaplet
в loginUser
позволяет мне проверять тип кода.Возможно, вам придется немного подправить вещи, чтобы справиться с фактическими ограничениями экземпляра.
Редактировать: Если описанная выше техника не позволяет вам прибавить b
каким-либо образом,и если предположить, что типы действительно должны быть такими же общими, как они написаны, то b
невозможно двусмысленно, и нет никакого способа обойти это.
Использование with authSnaplet
полностью исключает b
из фактического типа, но оставляет его полиморфным с ограничением класса.Это та же неопределенность, что и у выражения, подобного show . read
, с поведением, зависящим от экземпляра, но без возможности выбора одного.
Чтобы избежать этого, у вас есть примерно три варианта:
Явно сохраните неоднозначный тип, чтобы b
находился где-то в фактическом типе loginUser
, а не только в контексте.Это может быть нежелательным по другим причинам в контексте вашего приложения.
Удалите полиморфизм, применяя только with authSnaplet
к соответствующим мономорфным значениям.Если типы известны заранее, нет места для двусмысленности.Это потенциально означает отказ от некоторого полиморфизма в ваших обработчиках, но, разбивая вещи на части, вы можете ограничить мономорфизм только кодом, который заботится о том, что такое b
.
Сделайте ограничения класса сами по себе однозначными,Если три параметра типа HasAuth
на практике взаимозависимы до некоторой степени, так что для любых s
и u
будет только один действительный экземпляр, то функциональная зависимость от других до b
будетвполне уместно.