packages feed

calamity-0.1.8.0: src/Calamity/Internal/GenericCurry.hs

-- | Generic arity curry/ uncurry
module Calamity.Internal.GenericCurry
    ( Curry(..)
    , Uncurry(..) ) where

import           Data.Typeable

import           GHC.TypeNats

class Curry t where
  type Curried t
  type Parameters t

  curryG :: t -> Curried t

type family CurryInstanceSelector t :: Nat where
  CurryInstanceSelector (a -> b -> c -> d -> e -> f -> r) = 6
  CurryInstanceSelector (a -> b -> c -> d -> e -> r) = 5
  CurryInstanceSelector (a -> b -> c -> d -> r) = 4
  CurryInstanceSelector (a -> b -> c -> r) = 3
  CurryInstanceSelector (a -> b -> r) = 2
  CurryInstanceSelector (a -> r) = 1

class Curry' (flag :: Nat) t where
  type Curried' (flag :: Nat) t
  type Parameters' (flag :: Nat) t

  curryG' :: Proxy flag -> t -> Curried' flag t

instance (CurryInstanceSelector t ~ flag, Curry' flag t) => Curry t where
  type Curried t = Curried' (CurryInstanceSelector t) t
  type Parameters t = Parameters' (CurryInstanceSelector t) t

  curryG = curryG' (Proxy @flag)

instance Curry' 6 ((a, b, c, d, e, f) -> r) where
  type Curried' 6 ((a, b, c, d, e, f) -> r) = a -> b -> c -> d -> e -> f -> r
  type Parameters' 6 ((a, b, c, d, e, f) -> r) = (a, b, c, d, e, f)

  curryG' _ fn a b c d e f = fn (a, b, c, d, e, f)

instance Curry' 5 ((a, b, c, d, e) -> r) where
  type Curried' 5 ((a, b, c, d, e) -> r) = a -> b -> c -> d -> e -> r
  type Parameters' 5 ((a, b, c, d, e) -> r) = (a, b, c, d, e)

  curryG' _ fn a b c d e = fn (a, b, c, d, e)

instance Curry' 4 ((a, b, c, d) -> r) where
  type Curried' 4 ((a, b, c, d) -> r) = a -> b -> c -> d -> r
  type Parameters' 4 ((a, b, c, d) -> r) = (a, b, c, d)

  curryG' _ fn a b c d = fn (a, b, c, d)

instance Curry' 3 ((a, b, c) -> r) where
  type Curried' 3 ((a, b, c) -> r) = a -> b -> c -> r
  type Parameters' 3 ((a, b, c) -> r) = (a, b, c)

  curryG' _ fn a b c = fn (a, b, c)

instance Curry' 2 ((a, b) -> r) where
  type Curried' 2 ((a, b) -> r) = a -> b -> r
  type Parameters' 2 ((a, b) -> r) = (a, b)

  curryG' _ fn a b = fn (a, b)

instance Curry' 1 (a -> r) where
  type Curried' 1 (a -> r) = a -> r
  type Parameters' 1 (a -> r) = a

  curryG' _ fn = fn

class Uncurry t where
  type Uncurried t

  uncurryG :: t -> Uncurried t

class Uncurry' (flag :: Nat) t where
  type Uncurried' (flag :: Nat) t

  uncurryG' :: Proxy flag -> t -> Uncurried' flag t

instance (CurryInstanceSelector t ~ flag, Uncurry' flag t) => Uncurry t where
  type Uncurried t = Uncurried' (CurryInstanceSelector t) t

  uncurryG = uncurryG' (Proxy @flag)

instance Uncurry' 6 (a -> b -> c -> d -> e -> f -> r) where
  type Uncurried' 6 (a -> b -> c -> d -> e -> f -> r) = (a, b, c, d, e, f) -> r

  uncurryG' _ fn (a, b, c, d, e, f) = fn a b c d e f

instance Uncurry' 5 (a -> b -> c -> d -> e -> r) where
  type Uncurried' 5 (a -> b -> c -> d -> e -> r) = (a, b, c, d, e) -> r

  uncurryG' _ f (a, b, c, d, e) = f a b c d e

instance Uncurry' 4 (a -> b -> c -> d -> r) where
  type Uncurried' 4 (a -> b -> c -> d -> r) = (a, b, c, d) -> r

  uncurryG' _ f (a, b, c, d) = f a b c d

instance Uncurry' 3 (a -> b -> c -> r) where
  type Uncurried' 3 (a -> b -> c -> r) = (a, b, c) -> r

  uncurryG' _ f (a, b, c) = f a b c

instance Uncurry' 2 (a -> b -> r) where
  type Uncurried' 2 (a -> b -> r) = (a, b) -> r

  uncurryG' _ f (a, b) = f a b

instance Uncurry' 1 (a -> r) where
  type Uncurried' 1 (a -> r) = a -> r

  uncurryG' _ f = f