我想提出一种更系统的方法来回答这个问题,并展示一些示例,这些示例不使用诸如“底”值或无限数据类型之类的任何特殊技巧。
类型构造函数何时不具有类型类实例?
通常,类型构造函数可能无法拥有某个类型类的实例有两个原因:
- 无法实现类型类中所需方法的类型签名。
- 可以实现类型签名,但不能满足必需的法律。
第一种示例比第二种示例容易,因为对于第一类,我们只需要检查一个人是否可以使用给定类型签名来实现一个函数,而对于第二种,则需要证明没有实现可能会满足法律。
具体例子
关于type参数a
,这是一个矛盾的东西,而不是一个函子,因为它a
处于矛盾的位置。用类型签名实现一个函数是不可能的(a -> b) -> F z a -> F z b
。
即使fmap
可以实现的类型签名,也不是合法的仿函数的类型构造函数:
data Q a = Q(a -> Int, a)
fmap :: (a -> b) -> Q a -> Q b
fmap f (Q(g, x)) = Q(\_ -> g x, f x) -- this fails the functor laws!
这个示例的奇妙之处在于,即使它不可能用作函子,因为它在反位置使用,我们也可以实现fmap
正确的类型。因此,上面显示的这种实现方式具有误导性-尽管它具有正确的类型签名(我相信这是该类型签名的唯一可能的实现方式),但并不满足函子定律。例如,≠ ,因为is ,但是is 。F
a
fmap
fmap id
id
let (Q(f,_)) = fmap id (Q(read,"123")) in f "456"
123
let (Q(f,_)) = id (Q(read,"123")) in f "456"
456
实际上,F
它只是一个发音器,它既不是函子也不是冲突器。
由于pure
无法实现的类型签名而无法应用的合法函子:采用Writer monad (a, w)
并删除w
应该为类半体的约束。它是那么不可能构造类型的值(a, w)
出来的a
。
由于<*>
无法实现的类型签名而无法应用的函子:data F a = Either (Int -> a) (String -> a)
。
即使可以实现类型类方法的函子也不是合法的:
data P a = P ((a -> Int) -> Maybe a)
类型构造函数P
是一个函子,因为它a
仅在协变位置使用。
instance Functor P where
fmap :: (a -> b) -> P a -> P b
fmap fab (P pa) = P (\q -> fmap fab $ pa (q . fab))
类型签名的唯一可能的实现<*>
是一个始终返回的函数Nothing
:
(<*>) :: P (a -> b) -> P a -> P b
(P pfab) <*> (P pa) = \_ -> Nothing -- fails the laws!
但是,此实现不满足适用函子的身份定律。
Applicative
不能但不是的函子,Monad
因为bind
无法实现的类型签名。
我不知道任何这样的例子!
- 算符是
Applicative
,但不是Monad
因为法律不能满足,即使类型签名bind
可以实现。
这个例子引起了很多讨论,因此可以肯定地说,证明这个例子正确并不容易。但是有几个人通过不同的方法独立地对此进行了验证。请参阅“数据PoE是否为空”?配对一个单子吗?进行其他讨论。
data B a = Maybe (a, a)
deriving Functor
instance Applicative B where
pure x = Just (x, x)
b1 <*> b2 = case (b1, b2) of
(Just (x1, y1), Just (x2, y2)) -> Just((x1, x2), (y1, y2))
_ -> Nothing
证明没有合法的Monad
事例有点麻烦。非monadic行为的原因是,没有自然的方式可以实现bind
函数何时f :: a -> B b
可以返回Nothing
或Just
针对的不同值a
。
考虑一下Maybe (a, a, a)
,它也不是monad,然后尝试实现它,可能更清楚join
。人们会发现,没有直观上合理的实现方式join
。
join :: Maybe (Maybe (a, a, a), Maybe (a, a, a), Maybe (a, a, a)) -> Maybe (a, a, a)
join Nothing = Nothing
join Just (Nothing, Just (x1,x2,x3), Just (y1,y2,y3)) = ???
join Just (Just (x1,x2,x3), Nothing, Just (y1,y2,y3)) = ???
-- etc.
在所示的情况下???
,显然我们不能Just (z1, z2, z3)
以任何合理和对称的方式从六个不同的type值中产生a
。我们当然可以从这六个值中选择任意子集,例如,始终取第一个非空值,Maybe
但这不能满足单子法则。归还Nothing
也将不符合法律。
- 一个树状的数据结构,即使具有与之的关联性,也不是monad,
bind
但不符合身份定律。
通常的树状单子(或“带有函子形分支的树”)定义为
data Tr f a = Leaf a | Branch (f (Tr f a))
这是对函子的免费单子f
。数据的形状是一棵树,其中每个分支点都是一个“功能丰富的”子树。标准的二叉树将通过获得type f a = (a, a)
。
如果我们也通过以f
仿函数的形式制作叶子来修改此数据结构,则会得到我称为“ semimonad”的信息,它具有bind
满足自然性和关联性定律的要求,但是其pure
方法不能满足同一性定律之一。“ Semimonads是endofunctors类别中的半群,这是什么问题?” 这是类型类Bind
。
为简单起见,我定义join
方法而不是bind
:
data Trs f a = Leaf (f a) | Branch (f (Trs f a))
join :: Trs f (Trs f a) -> Trs f a
join (Leaf ftrs) = Branch ftrs
join (Branch ftrstrs) = Branch (fmap @f join ftrstrs)
分枝嫁接是标准的,但叶嫁接是非标准的,并产生Branch
。这对于关联性法则不是问题,但是打破了身份法则之一。
多项式类型何时具有monad实例?
函子Maybe (a, a)
和Maybe (a, a, a)
都不能被判为合法Monad
,尽管它们显然是Applicative
。
这些仿函数没有技巧-没有Void
或没有任何技巧bottom
,没有棘手的懒惰/严格性,没有无限的结构,没有类型类约束。该Applicative
实例是完全标准的。功能return
和bind
这些函子可以实现,但不满足单子法则。换句话说,这些函子不是单子,因为缺少了特定的结构(但是不容易理解到底缺少了什么)。例如,在函子上进行很小的更改就可以使其成为monad:data Maybe a = Nothing | Just a
是monad。另一个类似的函子data P12 a = Either a (a, a)
也是monad。
多项式monad的构造
通常,这里有一些构造可以Monad
从多项式类型中产生合法的。在所有这些构造中,M
一个单子是:
type M a = Either c (w, a)
w
什么半身像在哪里
type M a = m (Either c (w, a))
这里m
是任何单子,并w
为任何幺
type M a = (m1 a, m2 a)
这里m1
和m2
任何单子
type M a = Either a (m a)
m
单子在哪里
第一个结构是WriterT w (Either c)
,第二个结构是WriterT w (EitherT c m)
。第三结构是单子的成分之积:pure @M
被定义为的成分之积pure @m1
和pure @m2
,并join @M
通过省略跨产品数据(例如定义m1 (m1 a, m2 a)
映射到m1 (m1 a)
通过省略元组的第二部分):
join :: (m1 (m1 a, m2 a), m2 (m1 a, m2 a)) -> (m1 a, m2 a)
join (m1x, m2x) = (join @m1 (fmap fst m1x), join @m2 (fmap snd m2x))
第四种结构定义为
data M m a = Either a (m a)
instance Monad m => Monad M m where
pure x = Left x
join :: Either (M m a) (m (M m a)) -> M m a
join (Left mma) = mma
join (Right me) = Right $ join @m $ fmap @m squash me where
squash :: M m a -> m a
squash (Left x) = pure @m x
squash (Right ma) = ma
我检查了所有四个构造都产生合法的单子。
我猜想多项式单子没有其他构造。例如,函子Maybe (Either (a, a) (a, a, a, a))
不是通过任何这些构造获得的,因此不是单子函数。然而,Either (a, a) (a, a, a)
是一元,因为它是同构于三个单子的产品a
,a
和Maybe a
。另外,Either (a,a) (a,a,a,a)
是一元,因为它是同构的产品a
和Either a (a, a, a)
。
上面显示的四种构造将使我们能够获得任何数量的任意数量的产品的总和a
,例如Either (Either (a, a) (a, a, a, a)) (a, a, a, a, a))
以此类推。所有此类类型构造函数都将具有(至少一个)Monad
实例。
当然,此类单子可能存在哪些用例仍然有待观察。另一个问题是,Monad
通过构造1-4派生的实例通常不是唯一的。例如,type F a = Either a (a, a)
可以通过Monad
两种方式为类型构造函数提供实例:通过使用monad的构造4 (a, a)
以及通过类型同构的构造3 Either a (a, a) = (a, Maybe a)
。同样,为这些实现找到用例并不是立即显而易见的。
问题仍然存在-给定任意多项式数据类型,如何识别它是否具有Monad
实例。我不知道如何证明多项式单子没有其他构造。我认为到目前为止,还没有任何理论可以回答这个问题。
* -> *
)没有合适的类型fmap
?