{-# OPTIONS_HADDOCK show-extensions #-}

-- {-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs, NoMonoLocalBinds #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
-- {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
-- Needed for nested type family application:
{-# LANGUAGE UndecidableInstances #-}

{-# LANGUAGE NoIncoherentInstances #-}
{-# LANGUAGE NoMonomorphismRestriction #-}


--{-# LANGUAGE RankNTypes #-}

module Vivid.SynthDef.FromUA (
     FromUA(..)
   , fromUAWithDefaults
   , uaArgVal
   , uaArgValWDefault
   , DefaultArgs(..)
   , OverwritingArgs(..)
   , UA(..)
   , NoDefaults(..)
   , none
   , Args
   , SDBody

   , AllEqual
   ) where

-- import Vivid.SynthDef
import Vivid.SynthDef.ToSig
import Vivid.SynthDef.Types
-- import Vivid.SynthDef.TypesafeArgs

import qualified Data.List as L
import qualified Data.Map as Map
import Data.Monoid
import Data.Proxy
import GHC.Exts
import GHC.TypeLits

type SDBody a = SDBody' (SDBodyArgs a)

class FromUA (a :: *) where
   type UAsArgs a :: [Symbol]
   type SDBodyArgs a :: [Symbol]
   fromUA :: a -> SDBody a [(String, Signal)]

fromUAWithDefaults :: (
     FromUA a, FromUA b
   , SDBodyArgs a ~ SDBodyArgs b
   ) => DefaultArgs a -> OverwritingArgs b -> SDBody a [(String, Signal)]
fromUAWithDefaults (DefaultArgs defaultArgs) (OverwritingArgs overwritingArgs) = do
   defaultArgs' <- fromUA defaultArgs
   overwritingArgs' <- fromUA overwritingArgs
   return . Map.toList $
      Map.unionWith
         (\_defaultArg overwritingArg -> overwritingArg)
         (Map.fromList defaultArgs')
         (Map.fromList overwritingArgs')

-- Newtypes so we don't accidentally flip argument order:
newtype DefaultArgs a = DefaultArgs a
newtype OverwritingArgs a = OverwritingArgs a

data NoDefaults (args :: [Symbol])
   = NoDefaults
 deriving (Show, Eq, Ord, Read)

none :: NoDefaults args
none = NoDefaults

uaArgVal :: (FromUA as, Elem aToLookUp (UAsArgs as), KnownSymbol aToLookUp) => as -> proxy aToLookUp -> SDBody as Signal
uaArgVal uaArgs proxy = do
   allSigs <- fromUA uaArgs
   return $ case L.lookup (symbolVal proxy) (allSigs::[(String,Signal)]) of
      Just x -> x
      Nothing -> error $ "whaaaaaaaat?: " ++ symbolVal proxy

-- Note a typo in this one won't be caught -- it'll just use the default value
uaArgValWDefault :: (FromUA as, KnownSymbol aToLookUp, ToSig defaultVal (SDBodyArgs as)) => defaultVal -> as -> proxy aToLookUp -> SDBody as Signal
uaArgValWDefault defaultVal uaArgs proxy = do
   allSigs <- fromUA uaArgs
   case L.lookup (symbolVal proxy) (allSigs::[(String,Signal)]) of
      Just x -> return x
      Nothing -> toSig defaultVal

-- instance (args0 ~ args1) => FromUA (NoDefaults args0) args1 where
instance FromUA (NoDefaults args0) where
   type UAsArgs (NoDefaults args0) = '[]
   type SDBodyArgs (NoDefaults args0) = args0
   fromUA _ = return []

instance FromUA (UA a args0) where
   type UAsArgs (UA a sdArgs) = '[a]
   type SDBodyArgs (UA a args) = args
   fromUA :: UA a args -> SDBody (UA a args) [(String, Signal)]
   fromUA (UA x) = do
      y <- x
      return [(symbolVal (Proxy::Proxy a), y)]
      -- The LHS is like "freq" and the RHS is the value -- lhs isn't the 'foo' in 'A::A "foo"' ^^

instance (args0 ~ args1, KnownSymbol a {-, KnownSymbol b -}) => FromUA (UA a args0, UA b args1) where
   type UAsArgs (UA a args0, UA b args1) = '[a, b]
   type SDBodyArgs (UA a args0, UA b args1) = args0
   fromUA (a, b) = (<>) <$> fromUA a <*> fromUA b

instance (AllEqual '[as0,as1,as2], KnownSymbol a, KnownSymbol b)
         => FromUA (UA a as0, UA b as1, UA c as2) where
   type UAsArgs (UA a as0, UA b as1, UA c as2) = '[a, b, c]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2) = as0
   fromUA (a, b, c) =
      (<>) <$> fromUA a <*> fromUA (b, c)


instance (AllEqual '[as0,as1,as2,as3,as4], AllKnownSymbols '[a, b, c])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3) = '[a, b, c, d]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3) = as0
   fromUA (a, b, c, d) =
      (<>) <$> fromUA a <*> fromUA (b,c,d)



instance (AllEqual '[as0,as1,as2,as3,as4], AllKnownSymbols '[a,b,c,d] -- , KnownSymbol e --,
--     (SDBodyArgs (UA a as0)) ~ (UghRename (UA b as1, UA c as2, UA d as3, UA e as4))
          )
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4) = '[a, b, c, d, e]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4) = as0
   fromUA (a, b, c, d, e) = (<>) <$> fromUA a <*> fromUA (b,c,d,e)

-- 6:
instance (AllEqual '[as0,as1,as2,as3,as4,as5], AllKnownSymbols '[a,b,c,d,e,f])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5) = '[a, b, c, d, e, f]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5) = as0
   fromUA (a, b, c, d, e,f) = (<>) <$> fromUA a <*> fromUA (b,c,d,e,f)

-- 7:
instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6], AllKnownSymbols '[a,b,c,d,e,f,g])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5, UA g as6) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5,UA g as6) = '[a, b, c, d, e, f, g]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5,UA g as6) = as0
   fromUA (a,b,c,d,e,f,g) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g)


-- 8
instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7]
         , AllKnownSymbols '[a,b,c,d,e,f,g,h])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5,UA g as6,UA h as7) = '[a, b, c, d, e, f, g, h]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5,UA g as6,UA h as7) = as0
   fromUA (a,b,c,d,e,f,g,h) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h)


-- 9:
instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5,UA g as6,UA h as7,UA i as8) = '[a, b, c, d, e, f, g, h, i]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5,UA g as6,UA h as7,UA i as8) = as0
   fromUA (a,b,c,d,e,f,g,h,i) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i)


instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9) =
          '[a,b,c,d,e,f,g,h,i,j]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5,UA g as6,UA h as7,UA i as8,UA j as9) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j)


instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10) =
          '[a,b,c,d,e,f,g,h,i,j,k]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k)


instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11) =
          '[a,b,c,d,e,f,g,h,i,j,k,l]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l)


instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11,UA m as12) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m)


instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11,UA m as12,UA n as13) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n)


instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14
                ) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14
                  ) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o)


instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14,as15]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14,UA p as15
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14,UA p as15
                ) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14,UA p as15
                  ) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)


instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14,as15,as16]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                ) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                  ) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q)


instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14,as15,as16,as17]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                   ,UA r as17
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                ) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                  ) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r)


instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14,as15,as16,as17,as18]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                   ,UA r as17, UA s as18
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                ,UA s as18) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                  ,UA s as18) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s)


instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14,as15,as16,as17,as18,as19]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                   ,UA r as17, UA s as18,UA t as19
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                ,UA s as18,UA t as19) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                  ,UA s as18,UA t as19) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t)

instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14,as15,as16,as17,as18,as19,as20]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                   ,UA r as17, UA s as18,UA t as19,UA u as20
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                ,UA s as18,UA t as19,UA u as20
                ) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                  ,UA s as18,UA t as19,UA u as20
                  ) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u)

instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14,as15,as16,as17,as18,as19,as20,as21]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                   ,UA r as17, UA s as18,UA t as19,UA u as20,UA v as21
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                ,UA s as18,UA t as19,UA u as20,UA v as21
                ) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                  ,UA s as18,UA t as19,UA u as20,UA v as21
                  ) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v)

instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14,as15,as16,as17,as18,as19,as20,as21,as22]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                   ,UA r as17, UA s as18,UA t as19,UA u as20,UA v as21
                   ,UA w as22
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                ,UA s as18,UA t as19,UA u as20,UA v as21,UA w as22
                ) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                  ,UA s as18,UA t as19,UA u as20,UA v as21,UA w as22
                  ) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w)

instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14,as15,as16,as17,as18,as19,as20,as21,as22,as23]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                   ,UA r as17, UA s as18,UA t as19,UA u as20,UA v as21
                   ,UA w as22,UA x as23
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                ,UA s as18,UA t as19,UA u as20,UA v as21,UA w as22,UA x as23
                ) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                  ,UA s as18,UA t as19,UA u as20,UA v as21,UA w as22,UA x as23
                  ) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x)

instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14,as15,as16,as17,as18,as19,as20,as21,as22,as23,as24]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                   ,UA r as17, UA s as18,UA t as19,UA u as20,UA v as21
                   ,UA w as22,UA x as23,UA y as24
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                ,UA s as18,UA t as19,UA u as20,UA v as21,UA w as22,UA x as23
                ,UA y as24) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                  ,UA s as18,UA t as19,UA u as20,UA v as21,UA w as22,UA x as23
                  ,UA y as24) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y)

instance (AllEqual '[as0,as1,as2,as3,as4,as5,as6,as7,as8,as9,as10,as11,as12,as13,as14,as15,as16,as17,as18,as19,as20,as21,as22,as23,as24,as25]
         ,AllKnownSymbols '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z])
         => FromUA (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                   ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                   ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16
                   ,UA r as17, UA s as18,UA t as19,UA u as20,UA v as21
                   ,UA w as22,UA x as23,UA y as24,UA z as25
                   ) where
   type UAsArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                ,UA s as18,UA t as19,UA u as20,UA v as21,UA w as22,UA x as23
                ,UA y as24,UA z as25) =
          '[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z]
   type SDBodyArgs (UA a as0, UA b as1, UA c as2, UA d as3, UA e as4, UA f as5
                  ,UA g as6,UA h as7,UA i as8,UA j as9,UA k as10,UA l as11
                  ,UA m as12,UA n as13,UA o as14,UA p as15,UA q as16,UA r as17
                  ,UA s as18,UA t as19,UA u as20,UA v as21,UA w as22,UA x as23
                  ,UA y as24,UA z as25) = as0
   fromUA (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z) =
      (<>) <$> fromUA a <*> fromUA (b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z)


-- | \"UGen Arg\"
data UA (name :: Symbol) (args :: [Symbol]) where
   UA :: KnownSymbol name => SDBody' args Signal -> UA name args


type family AllEqual (a :: [[Symbol]]) :: Constraint where
   AllEqual '[] = ()
   AllEqual (a ': '[b]) = (a ~ b)
   AllEqual (a ': b ': cs) = (a ~ b, (AllEqual (a ': cs)))

type family AllKnownSymbols (a :: [ks]) :: Constraint where
   AllKnownSymbols '[] = ()
   AllKnownSymbols (ks0 ': kss) = (KnownSymbol ks0, AllKnownSymbols kss)

type family EachElems (forEach :: [Symbol]) args :: Constraint where
   EachElems (x ': xs) args = (Elem x args, EachElems xs args)
   EachElems '[] args = ()

type family Args (required :: [Symbol])
                 (optional :: [Symbol])
                 args
            :: Constraint where
   Args required optional args =
      ( Subset required (UAsArgs args)
      , Subset (UAsArgs args) (SetUnion required optional)
      , FromUA args
      -- , EachElems required (UAsArgs args)
      -- , EachElems optional (UAsArgs args)
      )