如何使用带镜头的IORef?

Sco*_*ott 4 haskell atomic haskell-lens ioref

想知道如何最好地将Control.Lens包与IORefs 结合起来.具体来说,我希望能够使用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
Run Code Online (Sandbox Code Playgroud)

Ørj*_*sen 6

原则上,镜头操作员实际上%%~是必需的,这只是一个方便的同义词id.但是,由于在atomicModifyIORef和中使用的元组排序中存在恼人的不兼容性(,) a Functor,因此需要进行一些交换才能工作.我不认为生成的运算符是预定义的,但我已经给它swappedId下面的初步名称.

请注意,Lens类型定义为

type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
Run Code Online (Sandbox Code Playgroud)

事实证明,如果你让它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
Run Code Online (Sandbox Code Playgroud)