2014-07-01 37 views
6

Sorun oldukça basit. BuControl.Lens öğesinden `over` öğesini nasıl kullanabilirim, ancak monadik bir eylem gerçekleştirebilir ve sonuçları toplayabilir miyim?

data Foo = Foo [Bar] 
data Bar = Boo | Moo Item Int 
data Item = Item String Int 

gibi görünür bir yapıya sahip ve ben burada böyle bu

let foos = [Foo [Boo, Moo (Item "bar" 20) 10]] 
over (traverse._Foo._Moo._1._Item._1) ("foo" ++) foos 

-- which yields [Foo [Boo, Moo (Item "foobar" 20) 10]] 

yapı olarak, veri yapısı içindeki Item s içeriğini değiştirmek için lens var değil önemli, sadece prizmalar ve derinlemesine iç içe bir şey kullanan bir örnek göstermek istedim.

Şimdi sorun, yalnızca String -> String yerine String -> IO String olmak üzere over'a geçirilen işleve ihtiyacım olmasıdır. Burada aradığım şeye benzer bir şey, mapM, ancak lenslerle. Böyle bir şey yapmak mümkün mü?

cevap

10

Mercek tam mapM gibidir ama alır traverseOf fonksiyonunu sağlayan bir mercek gibi map istediğiniz üzerinde (o lensler ve prims içeren bir geçişi, sürer). senin örneğin Yani

traverseOf :: Functor f => Iso s t a b  -> (a -> f b) -> s -> f t 
traverseOf :: Functor f => Lens s t a b  -> (a -> f b) -> s -> f t 
traverseOf :: Applicative f => Traversal s t a b -> (a -> f b) -> s -> f t 

, sadece kullanabilirsiniz:

traverseOf (traverse._Foo._Moo._1._Item._1) (... expression of type String -> IO String ...) foos 

da traverseOf bir operatör sürümü var, %%~ aradı. Eğer objektif kütüphane içinde lenslerin gösterimi ile biraz bildik iseniz


, bunu traverseOf = id fark edebilirsiniz! Yani, bu bilgiyle, sen sadece örnek yazabilirsiniz: (! Sadece mapM geçişi oluşturmaktır Hatta traverse kullanılan lensler prims sadece traverse gibi, ama daha özel /.)

(traverse._Foo._Moo._1._Item._1) (... expression of type String -> IO String ...) foos 

Ancak, bu sadece bir kenara çekilse de, netlik için traverseOf'u kullanmak isteyebilirsiniz.