{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
module Data.Row.Switch
( AppliesTo(..)
, switch
, caseon
)
where
import Data.Proxy
import Data.Bifunctor (Bifunctor(..))
import Data.Row.Internal
import Data.Row.Records
import Data.Row.Variants
class AppliesTo r f x | r x -> f, f r -> x where
applyTo :: f -> x -> r
instance AppliesTo r (x -> r) x where
applyTo = ($)
data SwitchData r v = SwitchData (Rec r) (Var v)
newtype Const2 x y z = Const2 { getConst2 :: x }
switch :: forall v r x. BiForall r v (AppliesTo x) => Var v -> Rec r -> x
switch v r = getConst2 $ biMetamorph @_ @_ @r @v @(AppliesTo x) @Either @SwitchData @(Const2 x) @(Const2 x)
Proxy doNil doUncons doCons $ SwitchData r v
where
doNil (SwitchData _ v) = impossible v
doUncons :: forall ℓ f τ ϕ ρ. (KnownSymbol ℓ, AppliesTo x f τ, HasType ℓ f ϕ, HasType ℓ τ ρ)
=> Label ℓ -> SwitchData ϕ ρ -> Either (SwitchData (ϕ .- ℓ) (ρ .- ℓ)) (Const2 x f τ)
doUncons l (SwitchData r v) = bimap (SwitchData $ lazyRemove l r) (Const2 . applyTo (r .! l)) $ trial v l
doCons _ (Left (Const2 x)) = Const2 x
doCons _ (Right (Const2 x)) = Const2 x
caseon :: forall v r x. BiForall r v (AppliesTo x) => Rec r -> Var v -> x
caseon = flip switch