几天前,我问了一个关于在自由单子的上下文中注入函子的问题。那里建议的解决方案基于Data Types à la Carte使用一个表示函子之间的一种包含关系的类。
-- | Class that represents the relationship between a functor 'sup' containing
-- a functor 'sub'.
class (Functor sub, Functor sup) => sub :-<: sup where
inj :: sub a -> sup a
-- | A functor contains itself.
instance Functor f => f :-<: f where
inj = id
-- | A functor is contained in the sum of that functor with another.
instance (Functor f, Functor g) => f :-<: (Sum f g) where
inj = InL
-- | If a functor 'f' is contained in a functor 'g', then f is contained in the
-- sum of a third functor, say 'h', with 'g'.
instance (Functor f, Functor g, Functor h, f :-<: g) => f :-<: (Sum h g) where
inj = InR . inj
现在考虑以下数据类型:
type WeatherData = String
data WeatherServiceF a = Fetch (WeatherData -> a) deriving (Functor)
data StorageF a = Store WeatherData a deriving (Functor)
以及具有以下类型的函数
fetch :: (WeatherServiceF :-<: g) => Free g WeatherData
从哪里来Free
的Control.Monad.Free
模块。
然后,如果我尝试按如下方式使用此功能:
reportWeather :: Free (Sum WeatherServiceF StorageF) ()
reportWeather = do
_ <- fetch
return ()
我收到一个重叠实例错误,说:
• Overlapping instances for WeatherServiceF
:-<: Sum WeatherServiceF StorageF
arising from a use of ‘fetch’
Matching instances:
two instances involving out-of-scope types
instance (Functor f, Functor g) => f :-<: Sum f g
instance (Functor f, Functor g, Functor h, f :-<: g) =>
f :-<: Sum h g
现在,我知道第一个是有效实例,但为什么第二个也被视为有效实例?如果我在第二种情况下实例化变量,我会得到
instance ( Functor WeatherServiceF
, Functor StorageF
, Functor WeatherServiceF
, WeatherServiceF :-<: StorageF
) => WeatherServiceF :-<: Sum WeatherServiceF g
这不应该是一个实例,因为WeatherServiceF :-<: StorageF
. 为什么 GHC 会推断出这样的例子?
我启用了以下实例:
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeOperators #-}