Тип вывода - не смог вывести Монаду
Я строю способ отображения диалога для пользователей.
data DialogConfig t m b e =
DialogConfig { _dialogConfig_title :: Dynamic t T.Text
, _dialogConfig_content :: b -> m (Dynamic t (Maybe b))
, _dialogConfig_footer :: Dynamic t (Maybe b) -> m (Event t e)
}
dialog :: MonadWidget t m =>
DialogConfig t m b e -> Event t b -> m (Event t (DialogEvent e))
Я хотел бы использовать какой-то экземпляр по умолчанию для инициализации DialogConfig
для dialog
функция, чтобы я мог использовать его как, например, defaultConfig{_dialogConfig_content=content}
, Тем не менее, я борюсь с типом вывода. Это работает:
confirmDialog :: forall t m. MonadWidget t m =>
T.Text -> Event t T.Text -> m (Event t ())
...
evt <- dialog
(DialogConfig { _dialogConfig_title = constDyn title
, _dialogConfig_content = content
, _dialogConfig_footer = buttons}
) contentEvt
Тем не менее, когда я использую некоторые по умолчанию DialogConfig
(например, здесь, непосредственно вставляя это), это не:
evt <- dialog
(DialogConfig { _dialogConfig_title = constDyn mempty
, _dialogConfig_content = const $ return $ constDyn Nothing
, _dialogConfig_footer = const $ return never }
{ _dialogConfig_title = constDyn title
, _dialogConfig_content = content
, _dialogConfig_footer = buttons}
) contentEvt
Ошибки:
Could not deduce (Reflex t0) arising from a use of ‘constDyn’ from the context (MonadWidget t m)
Could not deduce (Monad t1) arising from a use of ‘return’ from the context (MonadWidget t m)
я могу использовать ScopedTypeVariables
и введите конфигурацию по умолчанию в confirmDialog
как DialogConfig t m a b
и это работает, но разве не должно работать даже без него? Мне кажется, что типы довольно однозначны.
1 ответ
Как уже упоминалось в комментариях, проблема в том, что обновление записи может изменить тип записи (что может сначала удивить). Вот тест в GHCi:
> data T a = T { tA :: a }
> let x = T "foo"
> :t x
x :: T [Char]
> :t x { tA = True }
x { tA = True } :: T Bool
Итак, мы не можем определить значение по умолчанию:
> let def :: Read a => T a ; def = T (read "True")
> :t def :: T Bool
def :: T Bool :: T Bool
> :t def { tA = 5 }
Could not deduce (Read t0) arising from a use of ‘def’
The type variable ‘t0’ is ambiguous
Действительно, выше def
может быть любого типа.
Возможное решение может заключаться в том, чтобы заставить обновление иметь тот же тип, требуя T a -> T a
функция продолжения.
> let defF :: Read a => (T a -> T a) -> T a ; defF f = f (T (read "True"))
> :t defF (\d -> d { tA = False })
defF (\d -> d { tA = False }) :: T Bool
Выше d
это значение по умолчанию, которое по построению должно иметь тот же тип записи после обновления.
С линзами могут быть лучшие подходы.