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

Jean-Nicolas, Here is a variation on Corentin's solution: -- This function replaces every character that -- follows an 'a' with 'A' repA :: String -> String repA s = zipWith f (' ':s) s where f 'a' y = 'A' f x y = y Cheers, Hein
From: Jean-Nicolas Jolivet
I'm trying to iterate through each character of a string (that part I can do!) however, I need to apply a transformation to each character...based on the previous character in the string! This is the part I have no clue how to do! [snip] while i < my_string length: if my_string[i-1] == some_char: do something with my_string[i] else do something else with my_string[i]

I may have missed it in this thread, but if not, why didn't anyone suggest: trans [] = [] trans [x] = [x] trans ('a':_:xs) = 'a' : 'A' : trans xs trans (x:xs) = x : trans xs On Thu, 2010-04-29 at 05:46 -0700, Hein Hundal wrote:
Jean-Nicolas,
Here is a variation on Corentin's solution:
-- This function replaces every character that -- follows an 'a' with 'A'
repA :: String -> String
repA s = zipWith f (' ':s) s where f 'a' y = 'A' f x y = y
Cheers, Hein
From: Jean-Nicolas Jolivet
I'm trying to iterate through each character of a string (that part I can do!) however, I need to apply a transformation to each character...based on the previous character in the string! This is the part I have no clue how to do! [snip] while i < my_string length: if my_string[i-1] == some_char: do something with my_string[i] else do something else with my_string[i]
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Thu, Apr 29, 2010 at 3:52 PM, jean verdier
I may have missed it in this thread, but if not, why didn't anyone suggest:
trans [] = [] trans [x] = [x] trans ('a':_:xs) = 'a' : 'A' : trans xs trans (x:xs) = x : trans xs
While as a beginner (I still am !) I would come up with a solution like this one, on the long run it helps trying to solve those problem with maps, folds, filters, and zips: Eventually, you'll find the code more readable, easier to write, and there's perhaps a better chance that it can be optimised by ghc. David.

I understand that higher-order functions are incredibly powerful, and that
you can do essentially anything you might ever want while using only 'map'
and 'foldl'.
However, I have trouble believing that even experienced programmers wold
find such HOF-oriented code to be more readable than Mr Akgun's solution:
foo :: (a -> a -> a) -> [a] -> [a]
foo f (x:y:rest) = f x y : foo f (y:rest)
foo f _ = []
It seems to me that 'foo', as defined here, is a direct restatement of the
original program specification (the english one). Basically no translation
required.
If anyone here is enough of a veteran to prefer a map/fold implementation of
this spec, I would be interested to hear about the thought processes you
undertake when writing such code.
Thanks.
On Thu, Apr 29, 2010 at 10:22, David Virebayre
wrote:
On Thu, Apr 29, 2010 at 3:52 PM, jean verdier
wrote: I may have missed it in this thread, but if not, why didn't anyone suggest:
trans [] = [] trans [x] = [x] trans ('a':_:xs) = 'a' : 'A' : trans xs trans (x:xs) = x : trans xs
While as a beginner (I still am !) I would come up with a solution like this one, on the long run it helps trying to solve those problem with maps, folds, filters, and zips: Eventually, you'll find the code more readable, easier to write, and there's perhaps a better chance that it can be optimised by ghc.
David. _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
-- mac

On 29 April 2010 15:48, matthew coolbeth
I understand that higher-order functions are incredibly powerful, and that you can do essentially anything you might ever want while using only 'map' and 'foldl'.
Hello In this case neither map nor foldl are adequate as both provide an 'elementary' consumption pattern i.e. one item is consumed at each step. mapAccumL can be seeded with a state tracking the previous element, though as others have said you might want to define your own recursion scheme: replace2 :: (a -> a -> a) -> a -> [a] -> [a] replace2 f2 initial xs = snd $ mapAccumL fn initial xs where fn a x = (x, f2 a x) -- some example replaceCharAfterA :: String -> String replaceCharAfterA = replace2 fn 'Z' -- seed 'state' with 'Z' (wont match) where fn 'A' _ = '*' fn _ b = b demo1 = replaceCharAfterA "abcABC"
demo1 "abcA*C"
Best wishes Stephen

Hello all Correcting myself - in this case foldl is adequate - but it isn't pleasant as the list is produced in the wrong order: replaceCharAfterA_foldl' :: String -> String replaceCharAfterA_foldl' xs = reverse $ snd $ foldl' f ('Z',[]) xs where f ('A',cca) b = (b,'*':cca) f (_,cca) b = (b,b:cca) demo2 = replaceCharAfterA_foldl' "abcABC"
demo2 "abcA*C"
Best wishes Stephen

On Thu, Apr 29, 2010 at 10:48:15AM -0400, matthew coolbeth wrote:
I understand that higher-order functions are incredibly powerful, and that you can do essentially anything you might ever want while using only 'map' and 'foldl'.
However, I have trouble believing that even experienced programmers wold find such HOF-oriented code to be more readable than Mr Akgun's solution:
foo :: (a -> a -> a) -> [a] -> [a] foo f (x:y:rest) = f x y : foo f (y:rest) foo f _ = []
It seems to me that 'foo', as defined here, is a direct restatement of the original program specification (the english one). Basically no translation required.
If anyone here is enough of a veteran to prefer a map/fold implementation of this spec, I would be interested to hear about the thought processes you undertake when writing such code.
Instead of map/fold, I would absolutely prefer an implementation in terms of zipWith:
foo f xs = zipWith f xs (tail xs)
or perhaps
foo f xs = zipWith f (i:xs) xs
where i is some sort of initial value. It is immediately clear to me what this code does (match up "staggered" versions of xs, and zip them up with the function f). On the other hand, the solution you cited above takes me a a little time to read and digest, since it is much more "low-level". Consider:
foo :: (a -> a -> a) -> [a] -> [a] foo f (x:y:rest) = f x y : foo f (x:rest) foo f _ = []
This version is slightly (and crucially) different than the original. Can you spot how? I can easily imagine typing this wrong version by accident when trying to implement foo. And if it's that easy to make a silly but dramatic change, it must take a correspondingly large amount of energy to make sure you have understood all the details when reading the code. On the other hand, I can't think of very many ways to modify the zipWith implementation; there are far fewer pieces to get right and/or understand. Using higher-order functions and recursion combinators can be a strange discipline at first, but with practice it frees you to forget about details and think about things at a higher level. -Brent

Am Donnerstag 29 April 2010 16:48:15 schrieb matthew coolbeth:
I understand that higher-order functions are incredibly powerful, and that you can do essentially anything you might ever want while using only 'map' and 'foldl'.
No, you absolutely need foldr 8) (and foldl' is usually the better choice than foldl).
However, I have trouble believing that even experienced programmers wold find such HOF-oriented code to be more readable than Mr Akgun's solution:
foo :: (a -> a -> a) -> [a] -> [a] foo f (x:y:rest) = f x y : foo f (y:rest) foo f _ = []
It seems to me that 'foo', as defined here, is a direct restatement of the original program specification (the english one). Basically no translation required.
foo f xs = zipWith f xs (drop 1 xs) is equally readable - and that's it, I think; with experience, HOF-oriented code becomes as readable as the direct recursive code.
If anyone here is enough of a veteran to prefer a map/fold implementation of this spec, I would be interested to hear about the thought processes you undertake when writing such code.
No thought process, one just sees that it's a map/fold/... (after one has spent enough time looking for folds and such). Often before one sees the direct implementation. Do I prefer a map/fold/scan/zipWith implementation of such a spec? Yes and no. There's one definite advantage to coding (and thinking) in higher order functions/combinators. It helps identifying recurring patterns and then you write the combinator for that pattern. Once. You need only prove the correctness once. After that, you need only worry about the correctness of the combining function.
Thanks.
On Thu, Apr 29, 2010 at 10:22, David Virebayre
wrote:
On Thu, Apr 29, 2010 at 3:52 PM, jean verdier
wrote:
I may have missed it in this thread, but if not, why didn't anyone suggest:
trans [] = [] trans [x] = [x] trans ('a':_:xs) = 'a' : 'A' : trans xs trans (x:xs) = x : trans xs
While as a beginner (I still am !) I would come up with a solution like this one, on the long run it helps trying to solve those problem with maps, folds, filters, and zips: Eventually, you'll find the code more readable, easier to write, and there's perhaps a better chance that it can be optimised by ghc.
David.
participants (7)
-
Brent Yorgey
-
Daniel Fischer
-
David Virebayre
-
Hein Hundal
-
jean verdier
-
matthew coolbeth
-
Stephen Tetley