当一个泛型不会是单子吗?
Haskell允许围绕另一个定义新类型,从而创建一个“带有上下文的类型”。 因此,在例如data Time = Time (Int, Int)
- (h:m)和data Coord = Coord (Int, Int)
- (x,y)的情况下,可以区分(Int, Int)
)。 这些新类型将具有相关功能,因为知道包装的“基本”类型实际上是一个Int
。
更进一步的是,通过在data
子句中使用“类型参数”来创建“通用”类型,就像在着名的monad中一样: data Maybe t = Nothing | Just t
data Maybe t = Nothing | Just t
。 这些通用类型将被广泛的功能所使用,并且用于满足许多不同的需求,即:异常:可能,全局状态:状态,输入/输出:IO,不确定性:[],环境:读取器,记录器:作家。 这里有两个函数: return :: a -> ma
用于在类型a
周围构建上下文,以及(>>=) :: ma -> (a -> mb) -> mb
用于自动具有函数ma -> mb
基于前a -> mb
。 monad类汇总了这一点:
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
所以新的泛型类型必须定义什么意思return
和>>=
他们是Monad
一个实例。
在我看来,对于每种泛型都会发生这种情况,所以具体的问题是:
data MyThing t = ...
必须是Monad的实例? data MyThing t = ...
是Monad的一个实例是否方便? data MyThing t = ...
不能是Monad的实例吗? (除了微不足道的情况)。 为什么? data Time = Time (Int, Int)
,也是Monad? 以上解释的例子,修正和编辑是受欢迎和期望的。
谢谢。
这不是一个Monad ---它甚至不是一个Functor
。
-- from Data.Monoid
newtype Endo a = Endo { appEndo :: a -> a }
特别是, Endo
的类型参数a
在逆变和协变位置都显示出来 - 这种类型不能是Functor
或Contravariant
函数 - 它需要两者兼而有之。
当然,如果你只是略微推广它,你会得到Reader
monad
newtype Reader r a = Reader { runReader :: r -> a }
因为我们现在已经分开了类型参数的用法,例如一个是协变的,一个是逆变的。
在证明Endo
不能作为Functor
或Contravariant
因为它必须是两者,是否有任何数据类型都是? 有一个简单的技巧参数表明(1)有和(2)他们总是使用幻影参数。
我们将使用无数据类型( void
包提供了一个,但很容易重新实现)。 关于空数据类型的有趣之处在于你可以使用一个产生absurd
的功能,该功能采用不可能的参数并返回任何内容。
data Void = Void Void -- there are no values of Void
-- ... unless there are values of Void
absurd :: Void -> a
absurd (Void v) = absurd v
然后,与Functor
和Contravariant
相结合,给我们一个非常有趣的功能
contramap absurd :: Contravariant f => f a -> f Void
fmap absurd :: Functor f => f Void -> f a
fmap absurd . contramap absurd
:: (Contravariant f, Functor f) => f a -> f b
换句话说,它可以让我们编写一种基于函数的coerce
,如果f
实际上包含任何类型的a
值,那么这是不可能a
,因此我们知道这样的f
必须使用a
作为幻影参数。
data Constant b a = Constant { runConstant :: b }
coerceConstant :: Constant a -> Constant b
coerceConstant = Constant . runConstant
instance Functor (Constant b) where
fmap _ = coerceConstant
instance Contravariant (Constant b) where
contramap _ = coerceConstant
这甚至给我们一种实现非常无聊的Monad
instance Monoid b => Monad (Constant b) where
return _ = Constant mempty
c >>= _ = coerceConstant c
举个完全不是monad的例子,考虑一下
data Shower a = Shower (a -> String)
这是一个与functor相反的(实际上是双重的):一个逆变函子。
contramap :: Contravariant f => (a -> b) -> f b -> f a
contramap f (Shower q) = Shower (q . f)
比较这一点
fmap f (Identity x) = Identity (f $ x)
一个逆变函数不能是一个(平凡的)单子,也不是类似的东西。 要明白为什么,你需要考虑实际上(即在分类理论中)单子是什么:它是一种内生函数的幺半群。 它必须是endo,因为关键操作join :: m (ma) -> ma
意味着应用m
两次会使您处于同一类别中。 因为,如果你要在任何fmap
对函数A -> B
进行fmap
,你将会沿着相同的方向前进:
fmap f :: m A -> m B
fmap (fmap f) :: m (m A) -> m (m B)
(对于comonads也是如此,它也是(协变的,不是逆向的)函数。在这里,操作是duplicate :: wa -> w (wa)
,这反过来却仍然保持在同一类别中。 )
对于逆变函数,这是行不通的! 原因是,
contramap f :: q B -> q A
contramap (contramap f) :: q (q A) -> q (q B)
即如果迭代函子,它会在逆变和协变之间不断翻转。 因此它不能形成任何像猿人结构这样的东西。
参数化类型的概念比只有一个参数行为类似monad的类型的特例更简单。
所以,不,不是每种类型(*->*)
必须是monad,它也不方便。
一个例子:
data HomogenousTriple a = T a a a
为什么以及该如何做Monad?
链接地址: http://www.djcxy.com/p/77365.html