short function to remove and replace an item

What if I have a list xs, and I want to remove one item and replace it with another? The item to remove can be detected by a predicate function. The order of the items doesn't matter. How about this: replaceItem :: (a -> Bool) -> a -> [a] -> [a] replaceItem p new xs = new : snd (partition p xs) This will actually replace all items that match the predicate with one copy of 'new'. It will also prepend 'new' even if no items match the predicate. For another challenge, can someone explain to me how to write this in point-free style? Thanks, Mike

Prelude> let replaceItem p n = map (\x -> if p x then n else x) Prelude> replaceItem odd 100 [1..10] [100,2,100,4,100,6,100,8,100,10] Michael P Mossey wrote:
What if I have a list xs, and I want to remove one item and replace it with another? The item to remove can be detected by a predicate function. The order of the items doesn't matter. How about this:
replaceItem :: (a -> Bool) -> a -> [a] -> [a] replaceItem p new xs = new : snd (partition p xs)
This will actually replace all items that match the predicate with one copy of 'new'. It will also prepend 'new' even if no items match the predicate.
For another challenge, can someone explain to me how to write this in point-free style?
-- Vlad Skvortsov, vss@73rus.com, http://vss.73rus.com

Am Donnerstag 02 April 2009 02:45:29 schrieb Michael P Mossey:
What if I have a list xs, and I want to remove one item and replace it with another? The item to remove can be detected by a predicate function. The order of the items doesn't matter. How about this:
From the description, I'd rather have expected something like replaceItem :: (a -> Bool) -> a -> [a] -> [a] replaceItem p new (x:xs) | p x = new : xs -- or new : replaceItem p new xs | otherwise = x : replaceItem p new xs replaceItem _ _ [] = [] which could also be nicely written as replaceItem p new xs = case break p xs of (front,_:back) -> front ++ new : back _ -> xs the multiple replace: map (\x -> if p x then new else x) xs
replaceItem :: (a -> Bool) -> a -> [a] -> [a] replaceItem p new xs = new : snd (partition p xs)
This could also be written as replaceItem p new xs = new : filter (not . p) xs
This will actually replace all items that match the predicate with one copy of 'new'. It will also prepend 'new' even if no items match the predicate.
For another challenge, can someone explain to me how to write this in point-free style?
replaceItem p new xs = new : snd (partition p xs) rewrite the right hand side as (new :) . snd . (partition p) $ xs Now you can drop the last argument (xs) replaceItem p new = (new :) . snd . partition p To move new to the end, rewrite the right hand side as ((:) new) . (snd . partition p) === (. (snd . partition p)) . (:) $ new Now you can drop the next parameter, new: replaceItem p = (. (snd . partition p)) . (:) To move the predicate p to the end, rewrite the right hand side as (.) (. (snd . partition p)) (:) === flip (.) (:) (. (snd . partition p)) === flip (.) (:) $ flip (.) (snd . partition p) === flip (.) (:) $ flip (.) ((snd .) . partition $ p) === flip (.) (:) . flip (.) $ ((snd .) . partition $ p) === flip (.) (:) . flip (.) . (snd .) . partition $ p Now you can drop the last parameter, p: replaceItem = flip (.) (:) . flip (.) . (.) snd . partition Prelude Data.List> let replaceItem = flip (.) (:) . flip (.) . (.) snd . partition in replaceItem even 7 [1 .. 20] [7,1,3,5,7,9,11,13,15,17,19] But please, don't write your code in that style. Getting rid of xs is fine, dropping new leads to hard to read code. Removing all arguments is sheer obfuscation. There's more to writing pointfree code than being able to, one must also know when to stop.
Thanks, Mike
Cheers, Daniel

On Wed, Apr 1, 2009 at 7:45 PM, Michael P Mossey
What if I have a list xs, and I want to remove one item and replace it with another? The item to remove can be detected by a predicate function. The order of the items doesn't matter. How about this:
replaceItem :: (a -> Bool) -> a -> [a] -> [a] replaceItem p new xs = new : snd (partition p xs)
This will actually replace all items that match the predicate with one copy of 'new'. It will also prepend 'new' even if no items match the predicate.
For another challenge, can someone explain to me how to write this in point-free style?
I used an intermediate helper function, but the replaceItem function is point free choose :: (a -> Bool) -> (a -> b) -> (a -> b) -> a -> b choose pred yes _ val | (pred val) = yes val choose _ _ no val = no val replaceItem :: (a -> Bool) -> a -> [a] -> [a] replaceItem pred rep = map (choose pred id (const rep))

On Wed, Apr 1, 2009 at 9:50 PM, Zachary Turner
On Wed, Apr 1, 2009 at 7:45 PM, Michael P Mossey
wrote: What if I have a list xs, and I want to remove one item and replace it with another? The item to remove can be detected by a predicate function. The order of the items doesn't matter. How about this:
replaceItem :: (a -> Bool) -> a -> [a] -> [a] replaceItem p new xs = new : snd (partition p xs)
This will actually replace all items that match the predicate with one copy of 'new'. It will also prepend 'new' even if no items match the predicate.
For another challenge, can someone explain to me how to write this in point-free style?
I used an intermediate helper function, but the replaceItem function is point free
choose :: (a -> Bool) -> (a -> b) -> (a -> b) -> a -> b choose pred yes _ val | (pred val) = yes val choose _ _ no val = no val
replaceItem :: (a -> Bool) -> a -> [a] -> [a] replaceItem pred rep = map (choose pred id (const rep))
Ok I looked at the OP again and apparently I didn't understand the wording of the question :P I just thought it said to replace each element in the list that matched the predicate with the new item. How about this? replaceItem :: [a] -> (a -> Bool) -> a -> [a] let replaceItem xs pred = (: filter (not.pred) xs) Note that I changed the order of the arguments, the value now comes last. But I think this still should be ok?
participants (4)
-
Daniel Fischer
-
Michael P Mossey
-
Vlad Skvortsov
-
Zachary Turner