haskell 有没有基于Monad类的货车Laarhoven光学器件?

ssgvzors  于 2023-01-31  发布在  其他
关注(0)|答案(1)|浏览(168)

据我所知,每个货车Laarhoven optic类型都可以通过类型构造函数上的约束来定义:

type Lens      s t a b = forall f. Functor f     => (a -> f b) -> s -> f t
type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t
-- etc.

如果我们选择Monad作为约束,它是否以一种有意义的方式形成某种“光学”?

type Something s t a b = forall f. Monad f => (a -> f b) -> s -> f t

我的直觉是,Monad约束可能限制太多,无法从这样的结构中获取任何值:因为Const函子不是Monad,所以我们不能通过将f特化为Const来导出类似view的函数,但是我们可以用Something类型做一些事情;我只是不清楚我们是否能用它做些特别有用的事情。
我感到好奇的原因是,货车Laarhoven光学器件的类型与修改“可变引用”类型(如IORef)的函数类型非常相似。

modifyIORefM :: MonadIO m => IORef a -> (a -> m a) -> () -> m ()

其在部分施加到X1 M9 N1 X上时具有如下形状

type SomethingIO s t a b = forall f. MonadIO f => (a -> f b) -> s -> f t

其中a = bs = t = ()。我不确定这是一个有意义的巧合还是无意义的巧合。

syqv5f0l

syqv5f0l1#

实际上,这样的光学器件是一个稍微不方便的Traversal
这是因为,实际上,我们使用Traversal

type Traversal s t a b = forall f. (Applicative f) => (a -> f b) -> (s -> f t)

两件事,从s得到一个a的列表,我们可以用Const函子来做:

toListOf :: Traversal s t a b -> s -> [a]
toListOf t = getConst . t (Const . (:[]))

并且用b s替换a s以将s转换为t。一种方法是使用State函子,并且忽略匹配a s和b s的计数的问题,我们有:

setListOf :: Traversal s t a b -> [b] -> s -> t
setListOf t bs s = evalState (t (\a -> state (\(b:bs) -> (b, bs))) s) bs

如果我们改为使用Monad约束的光学器件:

type TraversalM s t a b = forall f. (Monad f) => (a -> f b) -> (s -> f t)

我们仍然可以执行这两个操作,因为State是一个单子,所以setListOf操作可以使用相同的实现:

setListOfM :: Traversal s t a b -> [b] -> s -> t
setListOfM t bs s = evalState (t (\a -> state (\(b:bs) -> (b, bs))) s) bs

对于toListOf,没有Const [a]Monad示例,但是我们可以使用Writer单子来提取a的值,只要我们有一个虚拟的b值来满足类型检查器:

toListOfM :: TraversalM s t a b -> b -> s -> [a]
toListOfM t dummy_b s = execWriter (t (\a -> tell [a] >> pure dummy_b) s)

或者,因为Haskell有底部:

toListOfM' :: TraversalM s t a b -> s -> [a]
toListOfM' t s = execWriter (t (\a -> tell [a] >> pure undefined) s)

自包含代码:

import Data.Functor.Const
import Control.Monad.State
import Control.Monad.Writer

type Traversal s t a b = forall f. (Applicative f) => (a -> f b) -> (s -> f t)

toListOf :: Traversal s t a b -> s -> [a]
toListOf t = getConst . t (Const . (:[]))

setListOf :: Traversal s t a b -> [b] -> s -> t
setListOf t bs s = evalState (t (\a -> state (\(b:bs) -> (b, bs))) s) bs

type TraversalM s t a b = forall f. (Monad f) => (a -> f b) -> (s -> f t)

toListOfM :: TraversalM s t a b -> b -> s -> [a]
toListOfM t dummy_b s = execWriter (t (\a -> tell [a] >> pure dummy_b) s)

toListOfM' :: TraversalM s t a b -> s -> [a]
toListOfM' t s = execWriter (t (\a -> tell [a] >> pure undefined) s)

setListOfM :: TraversalM s t a b -> [b] -> s -> t
setListOfM t bs s = evalState (t (\a -> state (\(b:bs) -> (b, bs))) s) bs

listItems :: Traversal [a] [b] a b
listItems = traverse

listItemsM :: TraversalM [a] [b] a b
listItemsM = mapM

main = do
  -- as a getter
  print $ toListOf listItems [1,2,3]
  print $ toListOfM listItemsM 99 [1,2,3]  -- dummy value
  print $ toListOfM' listItemsM [1,2,3]    -- use undefined
  -- as a setter
  print $ setListOf listItems [4,5,6] [1,2,3]
  print $ setListOfM listItemsM [4,5,6] [1,2,3]

相关问题