Skip to content

Instantly share code, notes, and snippets.

@Lysxia
Created May 29, 2019 00:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Lysxia/10f1da354f051b2d2eb24f6aace1bf9c to your computer and use it in GitHub Desktop.
Save Lysxia/10f1da354f051b2d2eb24f6aace1bf9c to your computer and use it in GitHub Desktop.
{-# LANGUAGE
AllowAmbiguousTypes,
ScopedTypeVariables,
TypeApplications,
TypeFamilies,
UndecidableInstances,
FlexibleContexts,
DataKinds,
DeriveGeneric,
TypeOperators
#-}
import Data.Kind (Type)
import Data.Proxy
import Numeric.Natural
import GHC.Generics
import GHC.TypeNats
type family Arity (f :: Type -> Type) :: Nat
type instance Arity (M1 i c f) = Arity f
type instance Arity (f :*: g) = Arity f + Arity g
type instance Arity U1 = 0
type instance Arity (K1 i a) = 1
arity :: forall a. (Generic a, KnownNat (Arity (Rep a))) => Natural
arity = natVal (Proxy @(Arity (Rep a)))
data T = T Int Bool String
deriving Generic
main = print (arity @T) -- 3
@treeowl
Copy link

treeowl commented May 29, 2019

The type errors will be horrible. You can fix that using something like this:

type family Arity (x :: Type) (f :: Type -> Type) :: Nat
type instance Arity x (M1 i c f) = Arity x f
type instance Arity x (f :*: g) = Arity x f + Arity x g
type instance Arity _ U1 = 0
type instance Arity _ (K1 i a) = 1
type instance Arity x (_ :+: _) =
  TypeError ('Text "Cannot calculate the arity of "
             :<>: 'ShowType x
             :<>: 'Text " because it has multiple constructors.")
type instance Arity x V1 =
  TypeError ('Text "Cannot calculate the arity of "
             :<>: 'ShowType x
             :<>: 'Text " because it has no constructors.")

arity :: forall a. (Generic a, KnownNat (Arity a (Rep a))) => Natural

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment