请考虑以下愿望程序。
{-# LANGUAGE ExtensibleGADTs #-}
data Free a where
Lift :: a -> Free a
data Free (f a) => FreeFunctor f a where
Map :: (a -> b) -> FreeFunctor f a -> FreeFunctor f b
instance Functor (FreeFunctor f) where
fmap = Map
data FreeFunctor f a => FreeApplicative f a where
Apply :: FreeApplicative f (a -> b) -> FreeApplicative f a -> FreeApplicative f b
Pure :: a -> FreeApplicative f a
instance Applicative (FreeApplicative f) where
(<*>) = Apply
pure = Pure
data FreeApplicative m a => FreeMonad m a where
Bind :: FreeMonad m a -> (a -> FreeMonad m b) -> FreeMonad m b
instance Monad (FreeMonad m) where
(>>=) = Bind
这将引入substitutability的概念。例如,FreeApplicative f a
可以用FreeFunctor f a
代替,而不能用FreeMonad f a
代替。同样,FreeApplicative f a -> Int
可用FreeMonad f a -> Int
代替,FreeFunctor f a -> Int
不能代替。
subtyping的概念可以通过注入来捕获。
import Unsafe.Coerce
fromFreeToFreeFunctor :: Free (f a) -> FreeFunctor f a
fromFreeToFreeFunctor = unsafeCoerce
fromFreeFunctorToFreeApplicative :: FreeFunctor f a -> FreeApplicative f a
fromFreeFunctorToFreeApplicative = unsafeCoerce
fromFreeApplicativeToFreeMonad :: FreeApplicative m a -> FreeMonad m a
fromFreeApplicativeToFreeMonad = unsafeCoerce
编译器将在需要的地方插入这些注入。
我认为这是expression problem的很好的解决方案。然而,general consensus认为亚型多态性在Haskell中是有问题的。所以,我的问题是两个方面。
我尚未为可扩展GADT定义精确的语义。如果这似乎值得追求,那么我想为此编写一个GHC扩展。只是想把这个想法大肆宣传,并引起一些批评。