diff options
author | Paul Oliver <contact@pauloliver.dev> | 2025-01-03 11:01:20 -0800 |
---|---|---|
committer | Paul Oliver <contact@pauloliver.dev> | 2025-01-05 09:59:10 -0800 |
commit | 6a0d7f5c434c3564d0119befb6799fd77581050a (patch) | |
tree | f20bc998290211d2a895523417ad32e297b31af0 /ch11_11.2-i.hs |
Diffstat (limited to 'ch11_11.2-i.hs')
-rw-r--r-- | ch11_11.2-i.hs | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/ch11_11.2-i.hs b/ch11_11.2-i.hs new file mode 100644 index 0000000..ab9b0c2 --- /dev/null +++ b/ch11_11.2-i.hs @@ -0,0 +1,49 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE ExplicitNamespaces #-} + +import Data.Functor.Identity (Identity (Identity)) +import Data.Kind (Type) +import Data.Proxy (Proxy (Proxy)) +import Fcf (Eval, FindIndex, FromMaybe, Stuck, TyEq, type (=<<)) +import GHC.TypeLits (KnownNat, natVal) +import Unsafe.Coerce (unsafeCoerce) + +data OpenSum (f :: k -> Type) (ts :: [k]) where + UnsafeOpenSum :: Int -> f t -> OpenSum f ts + +type FindElem (key :: k) (ts :: [k]) = + FromMaybe Stuck =<< FindIndex (TyEq key) ts + +type Member t ts = + KnownNat (Eval (FindElem t ts)) + +findElem :: forall t ts. Member t ts => Int +findElem = fromIntegral $ natVal $ Proxy @(Eval (FindElem t ts)) + +inject :: forall f t ts. Member t ts => f t -> OpenSum f ts +inject = UnsafeOpenSum $ findElem @t @ts + +project :: forall f t ts. Member t ts => OpenSum f ts -> Maybe (f t) +project (UnsafeOpenSum i f) = + if i == findElem @t @ts + then Just $ unsafeCoerce f + else Nothing + +decompose :: OpenSum f (t ': ts) -> Either (f t) (OpenSum f ts) +decompose (UnsafeOpenSum 0 t) = Left $ unsafeCoerce t +decompose (UnsafeOpenSum n t) = Right $ UnsafeOpenSum (n - 1) t + +-- Exercise 11.2-i +-- Write `weaken :: OpenSum f ts -> OpenSum f (x ': ts)`. +weaken :: OpenSum f ts -> OpenSum f (x ': ts) +weaken (UnsafeOpenSum n t) = UnsafeOpenSum (n + 1) t + +-- Example usage: +type SumTypes = '[Bool, Int] + +osum1 :: OpenSum Identity SumTypes +osum1 = inject (Identity True) + +projVal :: Maybe (Identity Bool) +projVal = project osum1 |