想知道如何最好地将Control.Lens包与IORef组合起来。具体来说,我希望能够使用atomicModifyIORef和透镜,这样我就可以提供a -> (a, b)类型的函数,并从操作中返回一个值。代码片段:
let inc x = (x+1, x)
ior <- newIORef ((1, 1) :: (Int, Int))
thisShouldBe1 <- ior & atomicModifyIORef ?? _1 inc -- this is the bit I'm stuck on发布于 2014-08-21 13:17:02
原则上,所需的透镜操作符实际上是%%~,这只是id的一个方便的同义词。但是,由于atomicModifyIORef和(,) a Functor中使用的元组顺序存在令人讨厌的不兼容性,因此需要进行一些交换才能工作。我不认为得到的操作符是预先定义的,但我在下面给它起了一个初步的名称swappedId。
注意,Lens类型被定义为
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t事实证明,如果让f成为(,) a Functor,这几乎完全符合您希望使用的转换inc的类型,只不过您确实希望a成为元组的最后一个元素,而不是第一个。修复之后,下面是我最后得到的结果:
import Data.IORef
import Control.Lens
l `swappedId` f = f & mapping swapped %~ l
main = do
let inc x = (x+1, x)
ior <- newIORef ((1, 1) :: (Int, Int))
thisShouldBe1 <- atomicModifyIORef ior $ _1 `swappedId` inc
print thisShouldBe1
print =<< readIORef ior发布于 2014-08-21 18:33:57
我发现定义一个使用IORefes操作Lens的助手函数是很方便的。正如rjan Johansen所提到的,atomicModifyIORef使用与Functor实例(,)不同的对顺序,因此我们需要交换。由于您希望具有a -> (a, b)类型的函数,所以我们也需要交换这个函数。
{-# LANGUAGE RankNTypes #-}
import Control.Lens
import Data.IORef
import Data.Tuple (swap)
-- | Atomically modifies an 'IORef' using a lens
atomicModifyWithLens :: IORef a -> Lens a a b c -> (b -> (c, r)) -> IO r
atomicModifyWithLens ref l f =
atomicModifyIORef ref (swap . traverseOf l (swap . f))
main = do
let inc x = (x+1, x)
ior <- newIORef ((1, 1) :: (Int, Int))
thisShouldBe1 <- atomicModifyWithLens ior _1 inc
print thisShouldBe1https://stackoverflow.com/questions/25423793
复制相似问题