Haskell 当泛型类型不是monad时?
Haskell允许围绕另一个类型定义新类型,从而创建 . 因此,可以在以下情况下区分Haskell 当泛型类型不是monad时?,haskell,monads,Haskell,Monads,Haskell允许围绕另一个类型定义新类型,从而创建 . 因此,可以在以下情况下区分(Int,Int) 数据时间=时间(Int,Int)--(h:m)和数据坐标=坐标(Int,Int)--(x,y)。 这些新类型将具有相关函数,知道包装的“base”类型实际上是Int 进一步的一步是创建“泛型”类型,方法是使用data子句中的“类型参数”,如著名的monad:data-Maybe t=Nothing | Just t。 这类泛型类型将被广泛的函数和 寻址,即:异常:可能,全局状态:状态,输入/输
(Int,Int)
数据时间=时间(Int,Int)
--(h:m)和数据坐标=坐标(Int,Int)
--(x,y)。
这些新类型将具有相关函数,知道包装的“base”类型实际上是Int
进一步的一步是创建“泛型”类型,方法是使用data
子句中的“类型参数”,如著名的monad:data-Maybe t=Nothing | Just t
。
这类泛型类型将被广泛的函数和
寻址,即:异常:可能,全局状态:状态,输入/输出:IO,不确定性:[],环境:读取器,记录器:写入器。
这里出现了具有两个函数的便利性:return::a->ma
用于围绕类型a
构建上下文,以及(>>=)::ma->(a->mb)->mb
用于基于先前的a->mb
自动具有函数ma->mb
。monad类对此进行了总结:
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
因此,新的泛型类型必须定义return
和>=
的含义,以便它们成为Monad
的实例
在我看来,每种泛型类型都会出现这种情况,因此具体问题如下:
数据神话t=…
都必须是Monad的实例数据神话t=…
都是Monad的实例,这样方便吗数据神话t=…
都不能是Monad的实例吗?
(除了琐碎的案件)。为什么?datatime=Time(Int,Int)
,也是Monad,这有意思吗谢谢。参数化类型的概念比只有一个参数的类型的特例更一般,而这些参数的行为恰好与monad类似 所以,不,不是所有种类
(*->*)
的类型都必须是单子,这也不方便
例如:
data HomogenousTriple a = T a a a
为什么以及如何成为单子?要给出一个完全不是单子的例子,请考虑
data Shower a = Shower (a -> String)
这与函子有点相反(实际上是对偶的):a
将此与
fmap f (Identity x) = Identity (f $ x)
逆变函子不能是(非平凡的)单子,也不能是类似物。要知道为什么,你需要考虑什么是:它是一种内括约肌的幺半群。它必须是endo,因为关键的操作join::m(ma)->ma
意味着应用m
两次会使您处于同一类别。例如,如果您要将fmap
a功能a->B
覆盖到任意一侧,您将沿着相同的方向:
fmap f :: m A -> m B
fmap (fmap f) :: m (m A) -> m (m B)
(这同样适用于,它们也是(协变的,而不是逆变的)函子。在这里,操作是duplicate::w a->w(w a)
,它反过来,但仍然必须保持在同一类别中。)
对于逆变函子,这不起作用!原因是,
contramap f :: q B -> q A
contramap (contramap f) :: q (q A) -> q (q B)
i、 如果你迭代函子,它会在反变和协变之间切换。因此,它不能形成任何像幺半群结构这样的东西。这里有些东西不是单子,它甚至不是一个函子
-- from Data.Monoid
newtype Endo a = Endo { appEndo :: a -> a }
特别是,Endo
的类型参数a
同时显示在逆变和协变位置---这种类型不能是函子
或逆变
函子---它必须同时是这两种类型
当然,如果你只是稍微概括一下,你就会得到阅读器
单子
newtype Reader r a = Reader { runReader :: r -> a }
因为我们现在已经分离出类型参数的用法,一个是协变的,一个是逆变的
已经证明了Endo
不能是函子
或逆变
,因为它必须同时是这两种类型,是否存在同时是这两种类型的数据类型?有一个简单的技巧论证表明(1)存在,并且(2)它们总是使用幻象参数
我们将使用空数据类型(void
包提供了一种空数据类型,但很容易重新实现)。空数据类型的有趣之处在于,可以使用空数据类型生成荒谬的
,该函数接受一个不可能的参数并返回任何内容
data Void = Void Void -- there are no values of Void
-- ... unless there are values of Void
absurd :: Void -> a
absurd (Void v) = absurd v
然后,结合函子
和逆变
给我们提供了一个非常有趣的函数
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
换句话说,它允许我们编写一种基于函子的强制
,如果f
实际上包含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的类型)?Thx.实际上这是一个单子。它同构于一个有三个元素的类型上的读卡器单子!如果Ingo声称不能给
数据同源性指令a=ta a
一个monad实例,那么这个说法是错误的。@托梅利斯我不是这样说的-我声称a)一个人通常不需要它,b)甚至不是为了方便。或者,重复我自己的话:出于什么原因,我们应该为它创建一个Monad实例?bind
ForHomogeneousTriple
对应于组件操作do x啊是的,对于这样的问题,一个强制性的参考当然是,它详细讨论了函子
,单子
等的层次结构。@Ingo和leftaroundabout:很明显,你们两个提供了明显的答案,其中类型有一个参数,但有两个或更多的参数值不适合(直截了当地说)s
instance Monoid b => Monad (Constant b) where
return _ = Constant mempty
c >>= _ = coerceConstant c