Kat*_*nto 9 haskell lenses haskell-optics
据我了解,每个 van Laarhoven 光学类型都可以通过类型构造函数的约束来定义:
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.
Run Code Online (Sandbox Code Playgroud)
如果我们选择Monad
作为约束,它是否以有意义的方式形成某种“光学”?
type Something s t a b = forall f. Monad f => (a -> f b) -> s -> f t
Run Code Online (Sandbox Code Playgroud)
我的直觉是,Monad
约束可能过于严格,无法从这样的结构中获取任何值:由于Const
函子不是 a Monad
,我们无法通过专门化f
toConst
来派生view
类似函数。尽管如此,我们仍然可以用这种类型做一些Something
事情;我只是不清楚我们是否可以用它做任何特别有用的事情。
我很好奇的原因是 van Laarhoven 光学器件的类型与修改“可变引用”类型(如 )的函数类型非常相似IORef
。例如,我们可以轻松实现
modifyIORefM :: MonadIO m => IORef a -> (a -> m a) -> () -> m ()
Run Code Online (Sandbox Code Playgroud)
当部分应用于 时IORef
,其形状为
type SomethingIO s t a b = forall f. MonadIO f => (a -> f b) -> s -> f t
Run Code Online (Sandbox Code Playgroud)
哪里a = b
和s = t = ()
. 我不确定这是一个有意义的巧合还是毫无意义的巧合。
实际上,这样的光学器件有点不方便Traversal
。
这是因为,实际上,我们使用Traversal
:
type Traversal s t a b = forall f. (Applicative f) => (a -> f b) -> (s -> f t)
Run Code Online (Sandbox Code Playgroud)
为了两件事。a
从 an获取 s 的列表s
,我们可以使用Const
函子来实现:
toListOf :: Traversal s t a b -> s -> [a]
toListOf t = getConst . t (Const . (:[]))
Run Code Online (Sandbox Code Playgroud)
并将 s 替换a
为b
s 将 变成s
a t
。一种方法是使用仿函数,并忽略s 和sState
的计数匹配问题,我们有:a
b
setListOf :: Traversal s t a b -> [b] -> s -> t
setListOf t bs s = evalState (t (\a -> state (\(b:bs) -> (b, bs))) s) bs
Run Code Online (Sandbox Code Playgroud)
如果我们有一个使用Monad
约束的光学器件:
type TraversalM s t a b = forall f. (Monad f) => (a -> f b) -> (s -> f t)
Run Code Online (Sandbox Code Playgroud)
我们仍然可以执行这两个操作。由于State
是一个 monad,setListOf
操作可以使用相同的实现:
setListOfM :: Traversal s t a b -> [b] -> s -> t
setListOfM t bs s = evalState (t (\a -> state (\(b:bs) -> (b, bs))) s) bs
Run Code Online (Sandbox Code Playgroud)
对于toListOf
,没有 的Monad
实例Const [a]
,但我们可以使用Writer
monad 来提取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)
Run Code Online (Sandbox Code Playgroud)
或者,因为 Haskell 有底部:
toListOfM' :: TraversalM s t a b -> s -> [a]
toListOfM' t s = execWriter (t (\a -> tell [a] >> pure undefined) s)
Run Code Online (Sandbox Code Playgroud)
独立代码:
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]
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
87 次 |
最近记录: |