Возможно, есть более простой способ сделать это, но мне удалось определить values
с помощью вспомогательного класса типов POSN
, который в основном выполняет индукцию по спискам пустого списка уровня типа:
values :: forall r c. (Generic r, Code r ~ c, POSN c) => NP (K r) c
values = liftA_NP (mapKK (to . SOP)) posn
-- products of sums of nil
class POSN xss where
posn :: NP (K (NS (NP I) xss)) xss
instance POSN '[] where
posn = Nil
instance (SListI2 xss, POSN xss) => POSN ('[] ': xss) where
posn = let previous = posn @xss
in K (Z Nil) :* liftA_NP (mapKK S) previous
Внутренние NP
всегда являются Nil
, потому что они соответствуют аргументам каждого конструктора, а аргументов никогда не бывает.
Индуктивный шаг "добавляет один" к каждому изсуммы остальной части списка, в начале которого стоит «ноль».
Пример использования:
ghci> :set -XTypeApplications
ghci> values @Foo
K Bar :* K Baz :* Nil