6
> magicFunction 'l' '_' "hello world"
["he_lo world", "hel_o world", "hello wor_d"]

Is there such a magic function in the standard Prelude or can it be composed easily with other functions?

And no, this isn't homework, but still, please don't spend too much time hand-rolling your own complicated solution, I'd rather do that myself than waste your time ;) Just asking if it's in the standard.


EDIT: Here is my first attempt:

import Data.List (findIndices)

replace i y xs = take i xs ++ y : drop (i+1) xs

magicFunction x y xs = map (\i -> replace i y xs) (findIndices (== x) xs)

Can it be improved? Surely something like replace must be in the standard? I found replace :: Eq a => a -> a -> [a] -> [a] in Network.CGI.Protocol, but it has the wrong signature.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • Are you trying to make a profanity filter bypass? XD – Mysticial Jul 13 '12 at 16:53
  • What's wrong with `replace`'s signature? Set `a ~ Char` so `[a] ~ String`, and we have `Eq Char`, so what's the problem? – dave4420 Jul 13 '12 at 16:53
  • 1
    @dave4420 The first problem is that it's in `Network.CGI.Protocol`... Pretty random as an import for this kind of functionality (which you _can_ find in more appropriate locations) – Jedai Jul 13 '12 at 16:58
  • @dave4420 The problem is that it "Replaces all instances of a value in a list by another value", but I just want to replace *one* value, identified by an index. – fredoverflow Jul 13 '12 at 16:58
  • Well I was writing an awesome answer but basically, there's no replace the first occurrence of an element in a list in the standard lib... The truth is that I never needed such a function and it is easy to write as you did (though splitAt or span would probably be more efficient). Can I ask why you needed this ? – Jedai Jul 13 '12 at 17:18
  • @Jedai [yes](http://chat.stackoverflow.com/transcript/message/4519263#4519263) :) – fredoverflow Jul 13 '12 at 17:24
  • @Jedai I miss your answer. : ( – Nick Vaccaro Jul 13 '12 at 17:33
  • 1
    @Norla Well, if you miss it that much, why don't you simp – fredoverflow Jul 13 '12 at 17:35
  • 1
    @FredOverflow Ah, you want a `magicFunction :: a -> a -> [a] -> [[a]]` :-) Yes, you can do better than that, you only need to traverse the list once (your current attempt traverses the list once to get a list of indices, and then once for each of those indices). Try to write it using `foldr`. – dave4420 Jul 13 '12 at 17:36

2 Answers2

2

No, there isn't something like magicFunction in the standard libraries. But it's easy to write yourself, so unless it's an often-used function, there's no point putting it in a library. In addition to your version and Daniel Wagner's hint with tails and inits, here's a simple implementation:

magicFunction find replace = init . helper
  where
    helper (c:cs) = if c == find then ((replace:cs):) else id $ map (c:) (helper cs)
    helper [] = [[]]
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
1

There is nothing like this in the standard distribution. However, there's a well-known trick that could form the start of a solution:

Prelude Data.List> (\xs -> zip (inits xs) (tails xs)) "Hello, world!"
[("","Hello, world!"),("H","ello, world!"),("He","llo, world!"),("Hel","lo, world!"),("Hell","o, world!"),("Hello",", world!"),("Hello,"," world!"),("Hello, ","world!"),("Hello, w","orld!"),("Hello, wo","rld!"),("Hello, wor","ld!"),("Hello, worl","d!"),("Hello, world","!"),("Hello, world!","")]
Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380