使用Type Level Literals作为区分非空容器值(与幻像类型一样)的方法,使用类似的类型。
这很有效。 (要求GHC> = 7.6.1)
但是试图定义二元函数(eq)
eq :: (Eq a) => TMaybe (sym :: Symbol) a -> TMaybe (sym :: Symbol) a -> Bool
承认不同的值组,在使用时发出编译错误信号:
无法匹配类型"Just"' with
“Nothing”'
{-# LANGUAGE DataKinds, KindSignatures, GADTs, FlexibleInstances #-}
import GHC.TypeLits
data TMaybe :: Symbol -> * -> * where
TNothing :: TMaybe "Nothing" a
TJust :: a -> TMaybe "Just" a
nonEmpty :: Maybe a -> TMaybe "Just" a
nonEmpty (Just x) = TJust x
nonEmpty Nothing = error "invalid nonEmpty data"
-- this fromJust rejects TNothing at compile time
fromJust :: (sym ~ "Just") => TMaybe (sym :: Symbol) a -> a
fromJust (TJust x) = x
tmbToMaybe :: TMaybe (sym :: Symbol) a -> Maybe a
tmbToMaybe TNothing = Nothing
tmbToMaybe (TJust x) = Just x
mbToTNothing Nothing = TNothing
mbToTJust (Just x) = TJust x
instance Eq a => Eq (TMaybe (sym :: Symbol) a) where
TNothing == TNothing = True
TJust x == TJust y = x == y
_ == _ = False -- useless, equal types required
instance Ord a => Ord (TMaybe (sym :: Symbol) a) where
compare TNothing TNothing = EQ
compare (TJust x) (TJust y) = Prelude.compare x y
compare TNothing _ = LT -- useless, equal types required
compare _ TNothing = GT -- useless, equal types required
instance Functor (TMaybe (sym :: Symbol)) where
fmap _ TNothing = TNothing
fmap f (TJust a) = TJust (f a)
instance Monad (TMaybe "Just") where
(TJust x) >>= k = k x
(TJust _) >> k = k
return = TJust
fail _ = error "can't fail to TNothing"
--------------------------
-- defining eq to admit parameter types with different symbol
eq :: (Eq a) => TMaybe (sym :: Symbol) a -> TMaybe (sym :: Symbol) a -> Bool
eq TNothing TNothing = True
eq (TJust x) (TJust y) = x == y
eq _ _ = False
---------------------------
-- Test
main = do
print $ fromJust $ TJust (5::Int) -- type-checks
-- print $ fromJust TNothing -- as expected, does not type-check
-- print $ TNothing == TJust (5::Int) -- as expected, does not type-check, types required equal at function def.
print $ TNothing `eq` TJust (5::Int) -- does not type-check either
答案 0 :(得分:9)
嗯,你的类型
eq :: (Eq a) => TMaybe (sym :: Symbol) a -> TMaybe (sym :: Symbol) a -> Bool
要求两个参数具有相同的类型,因此编译器当然会拒绝尝试比较TMaybe "Nothing" a
和TMaybe "Just" a
。
如果您将类型更改为
eq :: (Eq a) => TMaybe (sym :: Symbol) a -> TMaybe (sym1 :: Symbol) a -> Bool
它编译和
TNothing `eq` TJust (5::Int)
评估为False
。 (然后,您需要在许多地方明确确定TNothing
的类型。)