[Haskell-beginners] Re: Iterating through a list of char...

Daniel Fischer daniel.is.fischer at web.de
Thu Apr 29 16:50:21 EDT 2010


Am Donnerstag 29 April 2010 21:37:15 schrieb Jean-Nicolas Jolivet:
> First I would like to thank everyone for the very interesting replies
> and suggestions I got so far!...
>
> I tried to implement (and at the very least understand) most of them!...
>
> To add to the context here, what I am trying to do is:
>
> -apply a "transformation" to a character (in my case, subtracting 42 to
> its ASCII value, which I obtain with chr(ord(c) - 42) -if the character
> is preceded by a specific character (that would be, an escape character,
> in this case '=') then subtract 106 to its value instead of 42... -if
> the character is the escape character itself, '=',  then skip it
> altogether

Ah, that complicates matters a little.
- What happens if ord c < 42 (ord c < 106, if c is preceded by the escape 
character?)
- What about escaped escape characters?

However,

foo xs = catMaybes $ zipWith f (' ':xs) xs
    where
        f _ '=' = Nothing
        f '=' c = Just (chr $ ord c - 106)
        f _ c   = Just (chr $ ord c - 42)

is still pretty simple, as is the direct recursion

foo = go ' '
    where
        go _ ('=' :cs) = go '=' cs
        go '=' (c:cs)  = chr (ord c - 106) : go c cs
        go _ (c:cs)    = chr (ord c - 42) : go c cs
        go _ _         = []

-- assuming that only characters > 'i' (chr 105) are escaped (or the escape 
character itself, but that should be dropped regardless).

fooGen :: Char -> (Char -> Char) -> (Char -> Char) -> String -> String
fooGen e esc norm str = catMaybes $ zipWith f (d:str) str
    where
        d = if e == maxBound then pred e else succ e
        f x y
          | y == e    = Nothing
          | x == e    = Just (esc y)
          | otherwise = Just (norm y)

is an easy generalisation.

> (keeping in mind that the next character needs to be
> escaped)...
>
> I managed to do it, however I'm not totally satisfied in the way I did
> it... the problem was that... as I just explained, in some cases, the
> character that is being processed has to be "skipped" (and by that I
> mean, not added to the resulting string). This happens when the
> processed character IS the escape character...
>
> What I did was to build a List of Maybe Char.... my function does the
> proper operation on the character and returns a "Just Char" when the
> character is processed, or Nothing when it is the escaped character...
> so basically I would end up with something like:  [Just 'f', Just 'o',
> Just 'o', Nothing]... I am mapping this using mapMaybe to end up with a
> proper String...
>
> Would there be any more efficient way of doing this?

That is already pretty efficient. The direct recursion is probably a bit 
more efficient, but I don't think the difference will be large.

> Considering that
> the escape character should NOT be added to the resulting string, is
> there any way I can avoid using the Maybe monad?

Sure, apart from the direct recursion,

fooGen e esc norm str = tail $ foldr f [] (d:str)
    where
        d = if e == maxBound then pred e else succ e
        f x (y:zs)
          | y == e    = x:zs
          | x == e    = x:esc y:zs
          | otherwise = x:norm y:zs
          f x [] = [x]

catMaybes and zipWith is clearer, though, and I don't think the foldr will 
perform better.

>
> Once again, thanks everyone for all the suggestions!
>
> Jean-Nicolas Jolivet



More information about the Beginners mailing list