SNet-0.1.0: SNet/Variants.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE TypeOperators #-}
module SNet.Variants
( Variants (..)
, unsafeGetPattern
, variantsToList
, VariantMap (..)
, getBestMatch
) where
import Prelude hiding (foldr)
import Control.Applicative
import Data.Foldable
import Data.Traversable
import SNet.Pattern
import SNet.Record
data Nat = Succ Nat | Zero
data Variants :: [[*]] -> Nat -> * where
Empty :: Variants '[] Zero
Variant :: Pattern p -> Variants ps n -> Variants (p ': ps) (Succ n)
unsafeGetPattern :: Integral i
=> Variants ps n
-> i
-> (forall p . Pattern p -> r)
-> r
unsafeGetPattern Empty _ _ = error "Bounds violation"
unsafeGetPattern (Variant p _) 0 f = f p
unsafeGetPattern (Variant _ s) n f = unsafeGetPattern s (n-1) f
variantsToList :: Variants ps n -> (forall p . Pattern p -> r) -> [r]
variantsToList Empty _ = []
variantsToList (Variant p ps) f = f p : variantsToList ps f
data VariantMap :: [[*]] -> * -> * where
EmptyMap :: VariantMap '[] v
MapVariant :: Pattern p -> v -> VariantMap ps v -> VariantMap (p ': ps) v
instance Foldable (VariantMap ps) where
foldr _ z EmptyMap = z
foldr f z (MapVariant _ v ps) = f v (foldr f z ps)
instance Functor (VariantMap ps) where
fmap _ EmptyMap = EmptyMap
fmap f (MapVariant p v ps) = MapVariant p (f v) (fmap f ps)
instance Traversable (VariantMap ps) where
traverse _ EmptyMap = pure EmptyMap
traverse f (MapVariant p v ps) = MapVariant p <$> f v <*> traverse f ps
getBestMatch :: VariantMap ps v -> Record Data -> v
getBestMatch vmap rec = snd $ helper vmap
where helper :: VariantMap ps v -> (Maybe Int, v)
helper EmptyMap = (Nothing, error "No match found!")
helper (MapVariant p v ps) = maxBy fst (match p rec, v) (helper ps)
maxBy f x y = if f x >= f y then x else y