Я не знаю точного контекста, в котором вам требуются эти SymVal (Vec a n)
экземпляры, но, вообще говоря, если у вас есть фрагмент кода, который требует экземпляр SymVal (Vec a n)
, то вы должны добавить его в качестве контекста:
foo :: forall (a :: Type) (n :: Nat). SymVal (Vec a n) => ...
Когда foo
вызывается с конкретным n
, решатель ограничений сокращает приложение семейства типов и использует экземпляры
instance ( SymVal p, SymVal q ) => SymVal (p,q)
В конце этого процесса решатель ограничений будет хотеть экземпляр для SymVal a
. Таким образом, вы сможете позвонить foo
:
- , если вы задаете заданное значение для
n
, позволяя приложениям семейства типов полностью сократить, и используете тип a
, который имеет экземпляр для SymVal
:
bar :: forall (a :: Type). SymVal a => ...
bar = ... foo @a @(S (S (S Z))) ...
baz :: ...
baz = ... foo @Float @(S Z) ... -- Float has a SymVal instance
- отложить поиск экземпляра, указав тот же контекст:
quux :: forall (a :: Type) (n :: Nat). SymVal (Vec a n) => ...
quux = ... foo @a @n ...
GHC не может автоматически вывести SymVal (Vec a n)
из SymVal a
, потому что без дальнейшего контекста он не может уменьшить приложение семейства типов и, следовательно, не знает, какой экземпляр выбрать. Если вы хотите, чтобы GHC мог выполнить этот вывод, вы должны явно указать n
в качестве аргумента. Это можно эмулировать с помощью синглетонов:
deduceSymVal :: forall (a :: Type) (n :: Nat). Sing n -> Dict (SymVal a) -> Dict (SymVal (Vec a n))
deduceSymVal sz@SZ Dict =
case sz of
( _ :: Sing Z )
-> Dict
deduceSymVal ( ss@(SS sm) ) Dict
= case ss of
( _ :: Sing (S m) ) ->
case deduceSymVal @a @m sm Dict of
Dict -> Dict
(Обратите внимание, что эти отвратительные операторы case будут исключены при применении типов в шаблонах, mais c'est la vie.)
Затем вы можете использовать эту функцию, чтобы GHC мог вывести ограничение SymVal (Vec a n)
из ограничения SymVal a
, при условии, что вы можете предоставить синглтон для n
(что равняется передаче n
явно как вместо того, чтобы быть параметрическим по нему):
flob :: forall (a :: Type) (n :: Nat). (SymVal a, SingI n) => ...
flob = case deduceSymVal @a (sing @n) Dict of
Dict -- matching on 'Dict' provides a `SymVal (Vec a n)` instance
-> ... foo @a @n ...