{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

module Data.Aeson.Schema.Utils.All
  ( All(..)
  ) where

import Data.Proxy (Proxy(..))

-- | A type family for traversing a type-level list.
class All f xs where
  mapAll :: forall a. (forall x. f x => Proxy x -> a) -> [a]
  mapAll forall (x :: k). f x => Proxy x -> a
f = (forall (x :: k). f x => Proxy x -> [a] -> [a]) -> [a] -> [a]
forall k k (f :: k -> Constraint) (xs :: k) a.
All f xs =>
(forall (x :: k). f x => Proxy x -> a -> a) -> a -> a
foldrAll @f @xs forall (x :: k). f x => Proxy x -> [a] -> [a]
f' []
    where
      f' :: forall x. f x => Proxy x -> [a] -> [a]
      f' :: Proxy x -> [a] -> [a]
f' Proxy x
proxy [a]
acc = Proxy x -> a
forall (x :: k). f x => Proxy x -> a
f Proxy x
proxy a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
acc

  foldrAll :: (forall x. f x => Proxy x -> a -> a) -> a -> a

instance All f '[] where
  foldrAll :: (forall (x :: k). f x => Proxy x -> a -> a) -> a -> a
foldrAll forall (x :: k). f x => Proxy x -> a -> a
_ a
acc = a
acc

instance (f x, All f xs) => All f (x ': xs) where
  foldrAll :: (forall (x :: a). f x => Proxy x -> a -> a) -> a -> a
foldrAll forall (x :: a). f x => Proxy x -> a -> a
f a
acc = Proxy x -> a -> a
forall (x :: a). f x => Proxy x -> a -> a
f (Proxy x
forall k (t :: k). Proxy t
Proxy @x) ((forall (x :: a). f x => Proxy x -> a -> a) -> a -> a
forall k k (f :: k -> Constraint) (xs :: k) a.
All f xs =>
(forall (x :: k). f x => Proxy x -> a -> a) -> a -> a
foldrAll @f @xs forall (x :: a). f x => Proxy x -> a -> a
f a
acc)