首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >泛型LensLike,如映射和遍历

泛型LensLike,如映射和遍历
EN

Stack Overflow用户
提问于 2016-06-22 19:03:16
回答 3查看 298关注 0票数 19

假设我想为MaybeT m a的内容创建一个“光学组件”

maybeTContents = _Wrapped .something. _Just

有这样的something吗?

例如,当m[]时,maybeTContents将为Traversal,但当m(->) Int时,仅为Setter

示例用法:

代码语言:javascript
复制
> MaybeT [Just 1, Nothing, Just 2] ^.. maybeTContents
[1, 2]
> runMaybeT (MaybeT (Just . ('e':)) & maybeTContents %~ ('H':)) "llo"
Just "Hello"
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-06-29 22:09:14

要做到这一点,一种方法是制作自己的类,为您使用的类型提供正确的光学效果:

代码语言:javascript
复制
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE RankNTypes             #-}

class Ocular f t where
  optic :: LensLike f (t a) (t b) a b

instance Settable f => Ocular f ((->) a) where
  optic = mapped

instance Functor f => Ocular f Identity where
  optic = _Wrapped

instance Applicative f => Ocular f [] where
  optic = traversed

instance Applicative f => Ocular f Maybe where
  optic = _Just

这将给出(->) s的设置器和[]的遍历等。

代码语言:javascript
复制
> let maybeTContents = _Wrapped . optic . _Just
> MaybeT [Just 1, Nothing, Just 2] ^.. maybeTContents
[1,2]
> runMaybeT (MaybeT (Just . ('e':)) & maybeTContents %~ ('H':)) "llo"
Just "Hello"

您还可以为MaybeTReaderT编写实例

代码语言:javascript
复制
instance (Applicative f, Ocular f m) => Ocular f (MaybeT m) where
  optic = _Wrapped . optic . _Just


instance (Ocular f m, Settable f) => Ocular f (ReaderT r m) where
  optic = _Wrapped . mapped . optic

> MaybeT [Just 1, Nothing, Just 2] ^.. optic
[1,2]
> runReaderT (ReaderT (\r -> [r,r+1]) & optic *~ 2) 1
[2,4]

请注意,Identity案例只是一个Lens,而不是一个Iso。为此,您需要在Ocular类中包含Profuctor。您也可以编写一个版本,允许以这种方式索引镜头和遍历。

票数 6
EN

Stack Overflow用户

发布于 2016-06-23 00:45:24

是!首先要注意的是,something必须具有类型Setter (并且,在不失一般性的前提下,还必须具有Setter')。至于哪种类型,让我们使用孔。

代码语言:javascript
复制
maybeTContents :: Setter' (MaybeT m a) a
maybeTContents =
  _Wrapped . _ . _Just

GHC告诉我们它需要为这个洞输入Settable f => (Maybe a -> f (Maybe a)) -> (m (Maybe a) -> f (m (Maybe a))类型。

通过一次Hackage之旅,我们认识到这种类型就是Setter' (m (Maybe a)) (Maybe a)。因此,修复u ~ Maybe a,我们可以更一般地重新表述这个问题:是否存在同时与Setter' [u] u exist和Setter' (Reader u) u统一的setter

但是,由于[]Reader都有函数器实例,我们可以求助于一个绝对经典的设置器mappedthe setter heard around the worldmapped的类型是mapped :: Functor f => Setter (f a) (f b) a b -当你有一个可用的函数器实例时,它证明了mapped = sets fmap是遵守所有设置器规则的值。

我们可以在这里看到这一点:

代码语言:javascript
复制
  % stack ghci
GHCi, version 7.10.3: http://www.haskell.org/ghc/  :? for help
Ok, modules loaded: none.
λ> import Control.Lens
λ> import Control.Monad.Trans.Maybe
λ> import Control.Monad.Trans.Reader
λ> MaybeT [Just 1, Nothing, Just 2, Nothing, Just 3] & _Wrapped . mapped . _Just .~ 100
MaybeT [Just 100,Nothing,Just 100,Nothing,Just 100]
λ> data A = A
λ> data B = B
λ> :t MaybeT (ReaderT (\r -> Identity (Just A)))
MaybeT (ReaderT (\r -> Identity (Just A)))
  :: MaybeT (ReaderT r Identity) A
λ> :t MaybeT (ReaderT (\r -> Identity (Just A))) & _Wrapped . mapped . _Just .~ B
MaybeT (ReaderT (\r -> Identity (Just A))) & _Wrapped . mapped . _Just .~ B
  :: MaybeT (ReaderT r Identity) B

由于没有ReaderTShow实例,为了说明setter是如何工作的,我只能生成两个全新的类型-- AB

我认为这个问题很好,因为它是lens包背后动机的核心。给定来自Traversable世界的fmapDefault,您可以将遍历修复为Identity来编写over。然后,您可以编写oversets的倒数,这样over . sets = idsets . over = id就可以了。然后,我们不得不得出结论,mapped = sets fmap是一种自然的setter,它遵循我们想要的setter的规则,其中最重要的是mapped . mapped . mapped(.)的组合。lens的其余部分很快就会跟进。

票数 8
EN

Stack Overflow用户

发布于 2016-06-29 23:23:02

以下是基于前面答案的几个示例:

代码语言:javascript
复制
> MaybeT [Just 1, Nothing, Just 2] ^.. _Wrapped . traverse . _Just
[1,2]
> runMaybeT (MaybeT (Just . ('e':)) & _Wrapped . collect . _Just %~ ('H':)) "llo"
Just "Hello"

例如,对于Traversal/Fold,我们使用traverse,对于Settercollect (或mapped)。

不幸的是,TraversableDistributive并不具备所有的实例:(->) r不是TraversableConst也不是Distributive (而且它们也不可能是AFAICS)。

如果你仔细想想,你会发现这是有道理的。TraversalDistributive是二重奏,因此我们使用collect来表示traverse的“另一个方向”。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37966128

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档