我经常读到
看起来身份monad是无用的。它不是......但那是另一个 主题。
所以有人能告诉我它是如何有用的吗?
答案 0 :(得分:17)
Identity
是monad,functors和applicative functors,0代表数字。它本身似乎毫无用处,但是在人们期望monad或(applicative)functor实际上什么都不做的地方经常需要它。
正如已经提到的,Identity
允许我们定义monad变换器,然后定义它们相应的monad,就像SomeT Identity
一样。
但这不是全部。通过monad来定义其他概念通常也很方便,这通常会增加很多灵活性。例如Conduit i m o
(另请参阅this tutorial)定义管道中可以请求类型为i
的数据的元素,可以生成类型为o
的数据,并使用monad {{ 1}}用于内部处理。然后可以使用
m
(其中($$) :: Monad m => Source m a -> Sink a m b -> m b
是Source
的别名,没有输入,Conduit
的{{1}}没有输出的别名。当管道中不需要有效的计算时,只需要纯代码,我们只需将Sink
专门化为Conduit
并运行这样的管道
m
Identity
也是“空”仿函数和应用仿函数:runIdentity (source $$ sink)
由另一个仿函数或应用仿函数组成,与原始函数同构。例如,Lens'
被定义为Identity
中的函数多态:
Identity
粗略地说,这样的镜头允许在Functor
内读取或操纵Functor f => (a -> f a) -> s -> f s
类型的某些内容,例如记录内的字段(有关镜头的介绍,请参阅this post)。如果我们将a
专门设为s
,我们就会
f
与
同构Identity
因此在(a -> Identity a) -> s -> Identity s
上给出更新功能,返回(a -> a) -> s -> s
上的更新功能。 (为了完整性:如果我们将a
专门设置为s
,我们会得到f
,这与Const a
同构,即(a -> Const b a) -> s -> Const b s
上的读者,在(a -> b) -> (s -> b)
上退回读者。)
答案 1 :(得分:11)
有时我使用的字段在某些上下文中是可选的记录(比如从JSON解析记录时),但在其他情况下是必需的。
我通过使用仿函数参数化记录并在每种情况下使用Maybe
或Identity
来解决这个问题。
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StandaloneDeriving #-}
data Query f = Query
{
_viewName :: String
, _target :: f Server -- Server is some type, it doesn't matter which
}
deriving (Generic)
解析JSON时,服务器字段是可选的:
instance FromJSON (Query Maybe)
但是我有一个像
这样的功能withDefaultServer :: Server -> Query Maybe -> Query Identity
withDefaultServer = undefined
返回_target
字段为必填字段的记录。
(但这个答案并没有使用任何关于Identity
的monadic。)
答案 2 :(得分:9)
它的一个用途是作为monad变换器堆栈的基础monad:不必提供两种类型Some :: * ->*
和SomeT :: (* -> *) -> * -> *
,只需通过设置{{1}来提供后者即可。 }。
另一个有点类似的用例(但完全脱离整个monad业务)是当你需要引用元组时:我们可以说type Some = SomeT Identity
是一个nullary元组,()
是一个二元组元组,(a, b)
是一个三元组,依此类推,但这对于一元情况有什么影响?说(a, b, c)
是a
的任何选择的一元元组通常都不令人满意,例如当我们构建类似Data.Tuple.Select
的类型类实例时,需要一些类型构造函数来表示明确的键。所以通过添加例如a
个Sel1
个实例迫使我们区分Identity a
(包含(a, b)
和a
的两元组)和{{1} (包含单个b
值的一元组)。
(请注意,Identity (a, b)
定义了自己的名为OneTuple
的类型,而不是重用(a, b)
,但它与Data.Tuple.Select
同构 - 实际上,它只是重命名 - 我认为它只存在以避免非Identity
依赖。)
答案 3 :(得分:3)
一个真正的用例是monad变换器堆栈的(纯)基础,例如
type Reader r = ReaderT r Identity