Ihr Beispielcode ist leider zu spärlich, um anzuzeigen, was Sie wirklich meinen. Ich vermute, dass Sie nach abhängigen Typen sind, wie n.m. suggested. Wenn das der Fall ist, ist es wahrscheinlich besser, etwas wie Agda anstatt Haskell anzusehen. Wenn Sie eine etwas sicherere Version von was Daniel Wagner suggested möchten, können Sie es mit dem reflection Paket erhalten.
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
module DynEnum (.... not including newtype constructors) where
import Data.Reflection
import Data.Proxy
import Data.Set (Set, splitMember, size, lookupIndex, fromList, elemAt, member, findMin, findMax)
import Data.Foldable
import Data.Bool
import Data.Type.Coercion
-- Just Enum
newtype Limited a s = Limited { unLimited :: a }
type role Limited representational nominal
-- We can safely conflate types of values that come
-- from the same set.
coerceLimited :: (Reifies s (Set a), Reifies t (Set a), Ord a)
=> Maybe (Coercion (Limited a s) (Limited a t))
coerceLimited
| reflect (Proxy :: Proxy s) == reflect (Proxy :: Proxy t)
= Just Coercion
| otherwise = Nothing
instance (Ord a, Reifies s (Set a)) => Enum (Limited a s) where
toEnum i
| 0 <= i && i < size values = Limited $ elemAt i values
| otherwise = error "Limited toEnum: out of range"
where values = reflect (Proxy :: Proxy s)
fromEnum x = case lookupIndex (unLimited x) (reflect x) of
Nothing -> error "Limited fromEnum: out of range"
Just i -> i
enumFrom (Limited a) = case splitMember a (reflect (Proxy :: Proxy s)) of
(_, False, s) -> fmap Limited $ toList s
(_, True, s) -> Limited a : fmap Limited (toList s)
enumFromTo (Limited a) (Limited b) = case splitMember a (reflect (Proxy :: Proxy s)) of
(_, inclFirst, s) -> case splitMember b s of
(t, inclLast, _) -> bool id (Limited a:) inclFirst
. (map Limited (toList t) ++)
$ bool [] [Limited b] inclLast
initialize :: Ord a
=> [a]
-> (forall s . Enum (Limited a s) => Proxy s -> r)
-> r
initialize vals f = reify (fromList vals) f
construct :: forall s a . (Ord a, Reifies s (Set a)) => a -> Maybe (Limited a s)
construct x
| x `member` reflect (Proxy :: Proxy s) = Just (Limited x)
| otherwise = Nothing
newtype Bound a b = Bound a deriving (Enum)
type role Bound representational nominal
instance Reifies b (a, a) => Bounded (Bound a b) where
minBound = Bound . fst $ reflect (Proxy :: Proxy b)
maxBound = Bound . snd $ reflect (Proxy :: Proxy b)
initializeBounded :: (a, a)
-> (forall b . Bounded (Bound a b) => Proxy b -> r)
-> r
initializeBounded bounds f = reify bounds f
newtype LimitedB a s b = LimitedB (Bound (Limited a s) b)
deriving instance (Ord a, Reifies s (Set a)) => Enum (LimitedB a s b)
deriving instance Reifies b (Limited a s, Limited a s) => Bounded (LimitedB a s b)
initializeLimitedB :: Ord a
=> [a]
-> (forall s b . (Enum (LimitedB a s b), Bounded (LimitedB a s b)) => Proxy s -> Proxy b -> r)
-> r
initializeLimitedB [] _f = error "Cannot initialize LimitedB with an empty list"
initializeLimitedB vals f = reify set $ \ps ->
reify (Limited (findMin set), Limited (findMax set)) $ \pb ->
f ps pb
where
set = fromList vals
gut Typen zur Laufzeit gelöscht werden (können Sie ein Beispiel geben - weil nicht ist, was Sie sind nur eine Art von 'isElem Wert Set' fragen, wo' Set' zur Laufzeit definiert?) Im Grunde – Carsten
Dies ist das Problem, das ich habe. Ich dachte, es könnte möglich sein, eine interne Repräsentation als ([erlaubt], Vielleicht Wert) zu haben, aber es hat keine sehr schöne Semantik. –
Können Sie mithilfe dieser hypothetischen Funktion einen imaginären Code anzeigen? Sprechen Sie über so etwas wie abhängige Typen? –