2014-07-01 12 views
6

Il problema è piuttosto semplice. Ho una struttura che sembra qualcosa di simileCome posso usare `over` da Control.Lens ma eseguire un'azione monadica e raccogliere i risultati?

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

e ho un obiettivo per cambiare i contenuti delle Item s all'interno della struttura dei dati, come ad esempio questo

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]] 

La struttura qui non è importante, volevo solo mostrare un esempio che utilizza prismi e qualcosa profondamente annidato.

Ora il problema è che ho bisogno che la funzione passata a over sia String -> IO String, anziché solo String -> String. Una cosa simile a quello che sto cercando qui è qualcosa come mapM, ma con lenti. È possibile fare qualcosa di simile?

risposta

10

Lens fornisce la funzione traverseOf, che è esattamente come mapM ma prende una lente simile (ci vuole un attraversamento, che comprende lenti e prims) su cui si desidera map.

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 

Così, per il tuo esempio, si può semplicemente utilizzare:

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

C'è anche una versione operatore del traverseOf, chiamato %%~.


Se sei un po 'familiarità con la rappresentazione di lenti all'interno della biblioteca della lente, si potrebbe notare che traverseOf = id! Così, con questa conoscenza, è possibile riscrivere l'esempio da solo: (! È anche utilizzato traverse che è solo mapM di costruire l'attraversamento lenti/prims sono proprio come traverse, ma più specifico.)

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

Ma questo è solo un accantonamento, potreste comunque voler usare traverseOf per chiarezza.

Problemi correlati