Change the list item if it contains any condition or adds a new one if not using Data.Lens

I have a list of records and I need a function that looks for a list for a record with the given name and changes the value of this record OR if no record corresponds to adding a new record to the resulting list. Here is my code:

import Control.Lens import Control.Applicative ((<$>), pure) import Data.List (any) data SomeRec = SomeRec { _name :: String, _val :: Int } $(makeLenses ''SomeRec) _find :: (a -> Bool) -> Simple Traversal [a] a _find _ _ [] = pure [] _find pred f (a:as) = if pred a then (: as) <$> fa else (a:) <$> (_find pred f as) changeOrCreate :: [SomeRec] -> String -> (Int -> Int) -> [SomeRec] changeOrCreate recs nameToSearch valModifier = if (any (\r -> r^.name == nameToSearch) recs) then over (_find (\r -> r^.name == nameToSearch)) (over val valModifier) recs else recs ++ [SomeRec nameToSearch (valModifier 0)] 

This works great, but I wonder if there is a more direct way to write this using Data.Lens (without if -construct)? Also, do I need to write a _find function or is there something equivalent in the library?

Update: here is the gist of the experiment: https://gist.github.com/SKoschnicke/5795863

+8
list haskell lenses
source share
3 answers

What about:

 changeOrCreate :: String -> (Int -> Int) -> [SomeRec] -> [SomeRec] changeOrCreate nameToSearch valModifier = pos . val %~ valModifier & outside (filtered (not . has pos)) %~ (. newRec) where pos :: Traversal' [SomeRec] SomeRec pos = taking 1 (traversed . filtered (anyOf name (== nameToSearch))) newRec = (SomeRec nameToSearch 0 :) 
+2
source share

I don’t know, but you can write something like

 changeOrCreate [] nf = [SomeRec n (f 0)] changeOrCreate (r:rs) nf | r^.name == n = (over val f) r:rs | otherwise = r: changeOrCreate rs nf 
+2
source share

So _find is not really Traversal :

 > [1..10] & over (_find odd) succ . over (_find odd) succ [2,2,4,4,5,6,7,8,9,10] > [1..10] & over (_find odd) (succ . succ) [3,2,3,4,5,6,7,8,9,10] 

The same feeling filtered not a workaround.

Getting the part can be mimicked with filtered (this is normal, as Fold has no laws):

 > [1..10] ^? _find even Just 2 > [1..10] ^? _find (> 20) Nothing > [1..10] ^? folded . filtered even Just 2 > [1..10] ^? folded . filtered (> 20) Nothing 

Now, assuming that the β€œmore direct path” is the smart Traversal : no, which is impossible, Traversal cannot change the structure of the thing passed.

+2
source share

All Articles