Discussion:
[Haskell-beginners] Iterating through a list of char...
Jean-Nicolas Jolivet
2010-04-28 14:56:37 UTC
Permalink
Hi there!

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!

I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
is:

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'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!


Jean-Nicolas Jolivet
Maciej Piechotka
2010-04-28 15:16:25 UTC
Permalink
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
I assume i > 0 as otherwise my_string[i-1] is illegal
Post by Jean-Nicolas Jolivet
do something with my_string[i]
else
do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
Very simple version:

func (x:xs) = x:helper x xs
func [] = []

helper p (x:xs) | p == some_char = x':helper x' xs
| otherwise = x'':helper x'' xs
where x' = doSomething x
x'' = doSomethingElse x
helper p [] = []

or (for helper):

helper p (x:xs) = let x' | p == some_char = doSomething x
| otherwise = doSomethingElse x
in x':helper x' xs
helper p [] = []

Advanced version (depends on state of character before change)

func s@(x:xs) = x:zipWith proc s xs
where proc (p, x) | p == some_char = doSomething x
| otherwise = soSomethingElse x

Advanced version:

func (x:xs) = let s = x:zipWith proc s xs
proc (p, x) | p == some_char = doSomething x
| otherwise = soSomethingElse x
in s

It can be also expressed using folds. Choose version which suits you
best.

Regards
Jean-Nicolas Jolivet
2010-04-28 15:39:52 UTC
Permalink
Thanks a lot! I love the fact that you included different versions! Will definitely look into each versions and try to understand them all!

Jean-Nicolas
Post by Maciej Piechotka
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
I assume i > 0 as otherwise my_string[i-1] is illegal
Post by Jean-Nicolas Jolivet
do something with my_string[i]
else
do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
func (x:xs) = x:helper x xs
func [] = []
helper p (x:xs) | p == some_char = x':helper x' xs
| otherwise = x'':helper x'' xs
where x' = doSomething x
x'' = doSomethingElse x
helper p [] = []
helper p (x:xs) = let x' | p == some_char = doSomething x
| otherwise = doSomethingElse x
in x':helper x' xs
helper p [] = []
Advanced version (depends on state of character before change)
where proc (p, x) | p == some_char = doSomething x
| otherwise = soSomethingElse x
func (x:xs) = let s = x:zipWith proc s xs
proc (p, x) | p == some_char = doSomething x
| otherwise = soSomethingElse x
in s
It can be also expressed using folds. Choose version which suits you
best.
Regards
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
Dupont Corentin
2010-04-28 15:40:04 UTC
Permalink
Hello,

I would do:

doSmthg a = if a == 'a' then (const 'A') else id

trans c = zipWith doSmthg (" " ++ c) c
trans "arga"
"aAga"

The idea is to zip the string with the same string with an offset of character.
I thing my solution could be cleaner by using Maybe monad to handle
the first character's problem.

Corentin
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
I assume i > 0 as otherwise my_string[i-1] is illegal
Post by Jean-Nicolas Jolivet
do something with my_string[i]
else
do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
func (x:xs) = x:helper x xs
func [] = []
helper p (x:xs) | p == some_char = x':helper x' xs
| otherwise = x'':helper x'' xs
where x' = doSomething x
x'' = doSomethingElse x
helper p [] = []
helper p (x:xs) = let x' | p == some_char = doSomething x
| otherwise = doSomethingElse x
in x':helper x' xs
helper p [] = []
Advanced version (depends on state of character before change)
where proc (p, x) | p == some_char = doSomething x
| otherwise = soSomethingElse x
func (x:xs) = let s = x:zipWith proc s xs
proc (p, x) | p == some_char = doSomething x
| otherwise = soSomethingElse x
in s
It can be also expressed using folds. Choose version which suits you
best.
Regards
Ozgur Akgun
2010-04-28 15:40:44 UTC
Permalink
Hi!

Since the function to apply depends on the current element, and the previous
element, you need to define what to do if an element doesn't have a
previous, namely the first element in the list. I guess then it'll be quite
easy to implement such a function using explicit recursion.

The function to apply at each step is of type :: a -> a -> a (take the
previous element, and this element, and generate an element to replace the
current element, right?)
The list is of type [a], and the result will be of type [a] again.

foo :: (a -> a -> a) -> [a] -> [a]
foo f (x:y:rest) = f x y : foo f (y:rest)
foo f _ = []

This function is ready-to-use, except a case to handle the first element. It
would simply delete the first element.

*> foo (+) [1,2,3]
[3,5]

You can of course have a function like callfoo, which will prepend the first
element untouched.

callfoo :: (a -> a -> a) -> [a] -> [a]
callfoo f (x:xs) = x : foo f (x:xs)


I would generalise on this a little bit more, and introduce a function to
handle the first element differently.

bar :: (a -> b) -> (a -> a -> b) -> [a] -> [b]
bar f g (x:xs) = f x : loop g (x:xs)
where loop t (i:j:rest) = t i j : loop t (j:rest)
loop _ _ = []
bar _ _ _ = []

I think, the best thing about this version is that it doesn't limit the
input and the output of the function to be of the same type! (Figuring out
the meaning of a's and b's is left to the reader)
Note that the loop function defined within bar is almost the same with foo
defined before.

to test:

*> bar id (+) [1,2,3]
[1,3,5]


Hope this will be helpful, and not confusing. If you feel confused, just
think about the types one more time :)

Best,
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
do something with my_string[i]
else
do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
Ozgur Akgun
Jonas Almström Duregård
2010-04-28 15:51:56 UTC
Permalink
Post by Ozgur Akgun
*> bar id (+) [1,2,3]
[1,3,5]
Incidentally, scanl1 (+) [1,2,3] == [1,3,5], i.e. scanl1 = bar id.

/Jonas
Post by Ozgur Akgun
Hi!
Since the function to apply depends on the current element, and the previous
element, you need to define what to do if an element doesn't have a
previous, namely the first element in the list. I guess then it'll be quite
easy to implement such a function using explicit recursion.
The function to apply at each step is of type :: a -> a -> a (take the
previous element, and this element, and generate an element to replace the
current element, right?)
The list is of type [a], and the result will be of type [a] again.
foo :: (a -> a -> a) -> [a] -> [a]
foo f (x:y:rest) = f x y : foo f (y:rest)
foo f _ = []
This function is ready-to-use, except a case to handle the first element. It
would simply delete the first element.
*> foo (+) [1,2,3]
[3,5]
You can of course have a function like callfoo, which will prepend the first
element untouched.
callfoo :: (a -> a -> a) -> [a] -> [a]
callfoo f (x:xs) = x : foo f (x:xs)
I would generalise on this a little bit more, and introduce a function to
handle the first element differently.
bar :: (a -> b) -> (a -> a -> b) -> [a] -> [b]
bar f g (x:xs) = f x : loop g (x:xs)
    where loop t (i:j:rest) = t i j : loop t (j:rest)
          loop _ _ = []
bar _ _ _ = []
I think, the best thing about this version is that it doesn't limit the
input and the output of the function to be of the same type! (Figuring out
the meaning of a's and b's is left to the reader)
Note that the loop function defined within bar is almost the same with foo
defined before.
*> bar id (+) [1,2,3]
[1,3,5]
Hope this will be helpful, and not confusing. If you feel confused, just
think about the types one more time :)
Best,
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
               do something with my_string[i]
       else
               do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
Ozgur Akgun
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
Dupont Corentin
2010-04-28 15:58:47 UTC
Permalink
Hello,
i have scanl1 (+) [1,2,3] == [1,3,6]
since scanl apply successive reducing.
am i missing something?
Post by Jonas Almström Duregård
Post by Ozgur Akgun
*> bar id (+) [1,2,3]
[1,3,5]
Incidentally, scanl1 (+) [1,2,3] == [1,3,5], i.e. scanl1 = bar id.
/Jonas
Post by Ozgur Akgun
Hi!
Since the function to apply depends on the current element, and the previous
element, you need to define what to do if an element doesn't have a
previous, namely the first element in the list. I guess then it'll be quite
easy to implement such a function using explicit recursion.
The function to apply at each step is of type :: a -> a -> a (take the
previous element, and this element, and generate an element to replace the
current element, right?)
The list is of type [a], and the result will be of type [a] again.
foo :: (a -> a -> a) -> [a] -> [a]
foo f (x:y:rest) = f x y : foo f (y:rest)
foo f _ = []
This function is ready-to-use, except a case to handle the first element. It
would simply delete the first element.
*> foo (+) [1,2,3]
[3,5]
You can of course have a function like callfoo, which will prepend the first
element untouched.
callfoo :: (a -> a -> a) -> [a] -> [a]
callfoo f (x:xs) = x : foo f (x:xs)
I would generalise on this a little bit more, and introduce a function to
handle the first element differently.
bar :: (a -> b) -> (a -> a -> b) -> [a] -> [b]
bar f g (x:xs) = f x : loop g (x:xs)
where loop t (i:j:rest) = t i j : loop t (j:rest)
loop _ _ = []
bar _ _ _ = []
I think, the best thing about this version is that it doesn't limit the
input and the output of the function to be of the same type! (Figuring out
the meaning of a's and b's is left to the reader)
Note that the loop function defined within bar is almost the same with foo
defined before.
*> bar id (+) [1,2,3]
[1,3,5]
Hope this will be helpful, and not confusing. If you feel confused, just
think about the types one more time :)
Best,
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
do something with my_string[i]
else
do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
Ozgur Akgun
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
Ozgur Akgun
2010-04-28 16:02:47 UTC
Permalink
Exactly:

*> bar id (+) [1..5]
[1,3,5,7,9]
*> scanl1 (+) [1..5]
[1,3,6,10,15]

But they are close enough, I guess :)
Post by Dupont Corentin
Hello,
i have scanl1 (+) [1,2,3] == [1,3,6]
since scanl apply successive reducing.
am i missing something?
Post by Jonas Almström Duregård
Post by Ozgur Akgun
*> bar id (+) [1,2,3]
[1,3,5]
Incidentally, scanl1 (+) [1,2,3] == [1,3,5], i.e. scanl1 = bar id.
/Jonas
Post by Ozgur Akgun
Hi!
Since the function to apply depends on the current element, and the previous
element, you need to define what to do if an element doesn't have a
previous, namely the first element in the list. I guess then it'll be quite
easy to implement such a function using explicit recursion.
The function to apply at each step is of type :: a -> a -> a (take the
previous element, and this element, and generate an element to replace
the
Post by Jonas Almström Duregård
Post by Ozgur Akgun
current element, right?)
The list is of type [a], and the result will be of type [a] again.
foo :: (a -> a -> a) -> [a] -> [a]
foo f (x:y:rest) = f x y : foo f (y:rest)
foo f _ = []
This function is ready-to-use, except a case to handle the first
element.
Post by Jonas Almström Duregård
Post by Ozgur Akgun
It
would simply delete the first element.
*> foo (+) [1,2,3]
[3,5]
You can of course have a function like callfoo, which will prepend the first
element untouched.
callfoo :: (a -> a -> a) -> [a] -> [a]
callfoo f (x:xs) = x : foo f (x:xs)
I would generalise on this a little bit more, and introduce a function
to
Post by Jonas Almström Duregård
Post by Ozgur Akgun
handle the first element differently.
bar :: (a -> b) -> (a -> a -> b) -> [a] -> [b]
bar f g (x:xs) = f x : loop g (x:xs)
where loop t (i:j:rest) = t i j : loop t (j:rest)
loop _ _ = []
bar _ _ _ = []
I think, the best thing about this version is that it doesn't limit the
input and the output of the function to be of the same type! (Figuring
out
Post by Jonas Almström Duregård
Post by Ozgur Akgun
the meaning of a's and b's is left to the reader)
Note that the loop function defined within bar is almost the same with
foo
Post by Jonas Almström Duregård
Post by Ozgur Akgun
defined before.
*> bar id (+) [1,2,3]
[1,3,5]
Hope this will be helpful, and not confusing. If you feel confused, just
think about the types one more time :)
Best,
On 28 April 2010 15:56, Jean-Nicolas Jolivet <
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
do something with my_string[i]
else
do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
Ozgur Akgun
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
Ozgur Akgun
Jonas Almström Duregård
2010-04-28 16:06:56 UTC
Permalink
5 or 6, does it really matter? ;)

Sorry about the confusion...

/J
Post by Dupont Corentin
Hello,
i have scanl1 (+) [1,2,3] == [1,3,6]
since scanl apply successive reducing.
am i missing something?
Post by Jonas Almström Duregård
Post by Ozgur Akgun
*> bar id (+) [1,2,3]
[1,3,5]
Incidentally, scanl1 (+) [1,2,3] == [1,3,5], i.e. scanl1 = bar id.
/Jonas
Post by Ozgur Akgun
Hi!
Since the function to apply depends on the current element, and the previous
element, you need to define what to do if an element doesn't have a
previous, namely the first element in the list. I guess then it'll be quite
easy to implement such a function using explicit recursion.
The function to apply at each step is of type :: a -> a -> a (take the
previous element, and this element, and generate an element to replace the
current element, right?)
The list is of type [a], and the result will be of type [a] again.
foo :: (a -> a -> a) -> [a] -> [a]
foo f (x:y:rest) = f x y : foo f (y:rest)
foo f _ = []
This function is ready-to-use, except a case to handle the first element. It
would simply delete the first element.
*> foo (+) [1,2,3]
[3,5]
You can of course have a function like callfoo, which will prepend the first
element untouched.
callfoo :: (a -> a -> a) -> [a] -> [a]
callfoo f (x:xs) = x : foo f (x:xs)
I would generalise on this a little bit more, and introduce a function to
handle the first element differently.
bar :: (a -> b) -> (a -> a -> b) -> [a] -> [b]
bar f g (x:xs) = f x : loop g (x:xs)
    where loop t (i:j:rest) = t i j : loop t (j:rest)
          loop _ _ = []
bar _ _ _ = []
I think, the best thing about this version is that it doesn't limit the
input and the output of the function to be of the same type! (Figuring out
the meaning of a's and b's is left to the reader)
Note that the loop function defined within bar is almost the same with foo
defined before.
*> bar id (+) [1,2,3]
[1,3,5]
Hope this will be helpful, and not confusing. If you feel confused, just
think about the types one more time :)
Best,
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
               do something with my_string[i]
       else
               do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
Ozgur Akgun
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
Hector Guilarte
2010-04-28 15:44:14 UTC
Permalink
Hey!

Keep passing the current char to your next call of the function (your next "iteration" as you said), that way you have the previos char in the current "iteration" and you can use it. The first time you call it make sure you call it with a dummy char that you know it will do what supposed to.

Greetings,

Hector Guilarte

Enviado desde mi dispositivo movil BlackBerry® de Digitel.

-----Original Message-----
From: Jean-Nicolas Jolivet <***@gmail.com>
Date: Wed, 28 Apr 2010 10:56:37
To: <***@haskell.org>
Subject: [Haskell-beginners] Iterating through a list of char...

Hi there!

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!

I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
is:

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'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!


Jean-Nicolas Jolivet
_______________________________________________
Beginners mailing list
***@haskell.org
http://www.haskell.org/mailman/listinfo/beginn
Hein Hundal
2010-04-29 12:46:14 UTC
Permalink
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
Post by 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]
        do something with
my_string[i]
    else
        do something else
with my_string[i]
jean verdier
2010-04-29 13:52:40 UTC
Permalink
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
Post by Hein Hundal
Jean-Nicolas,
-- 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
Post by 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]
do something with
my_string[i]
else
do something else
with my_string[i]
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
David Virebayre
2010-04-29 14:22:33 UTC
Permalink
Post by jean verdier
I may have missed it in this thread, but if not, why didn't anyone
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.
matthew coolbeth
2010-04-29 14:48:15 UTC
Permalink
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
Post by David Virebayre
Post by jean verdier
I may have missed it in this thread, but if not, why didn't anyone
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
http://www.haskell.org/mailman/listinfo/beginners
--
mac
Stephen Tetley
2010-04-29 17:40:56 UTC
Permalink
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
Stephen Tetley
2010-04-29 18:01:14 UTC
Permalink
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
Brent Yorgey
2010-04-29 18:00:47 UTC
Permalink
Post by 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'.
However, I have trouble believing that even experienced programmers wold
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
Post by matthew coolbeth
foo f xs = zipWith f xs (tail xs)
or perhaps
Post by matthew coolbeth
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
Post by matthew coolbeth
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
Daniel Fischer
2010-04-29 18:04:28 UTC
Permalink
Post by 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).
Post by matthew coolbeth
However, I have trouble believing that even experienced programmers
wold find such HOF-oriented code to be more readable than Mr Akgun's
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.
Post by matthew coolbeth
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.
Post by matthew coolbeth
Thanks.
On Thu, Apr 29, 2010 at 10:22, David Virebayre
Post by David Virebayre
Post by jean verdier
I may have missed it in this thread, but if not, why didn't anyone
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.
Jean-Nicolas Jolivet
2010-04-29 19:37:15 UTC
Permalink
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 (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? Considering that the escape character should NOT be added to the resulting string, is there any way I can avoid using the Maybe monad?

Once again, thanks everyone for all the suggestions!

Jean-Nicolas Jolivet
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
do something with my_string[i]
else
do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
Ozgur Akgun
2010-04-29 20:26:50 UTC
Permalink
I won't attempt writing a general-case function now. If I understood your
(rather long) description correctly, you want to
- subtract 42 from the ascii value of the char, except when it is preceeded
by '=', in which case you subtract 106 instead.

foo :: [Char] -> [Char]
foo ('=':x:xs) = chr (ord x - 106) : foo xs
foo (x:xs) = chr (ord x - 42) : foo xs
foo _ = []

Hope I understood the problem correctly.
Best,
Post by 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!...
-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 (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? Considering that the
escape character should NOT be added to the resulting string, is there any
way I can avoid using the Maybe monad?
Once again, thanks everyone for all the suggestions!
Jean-Nicolas Jolivet
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
do something with my_string[i]
else
do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
Ozgur Akgun
matthew coolbeth
2010-04-29 20:31:14 UTC
Permalink
This works, except for the case where '=' appears more than twice
consecutively. A string of multiple '=' should be treated as a single '='.
Post by Ozgur Akgun
I won't attempt writing a general-case function now. If I understood your
(rather long) description correctly, you want to
- subtract 42 from the ascii value of the char, except when it is preceeded
by '=', in which case you subtract 106 instead.
foo :: [Char] -> [Char]
foo ('=':x:xs) = chr (ord x - 106) : foo xs
foo (x:xs) = chr (ord x - 42) : foo xs
foo _ = []
Hope I understood the problem correctly.
Best,
Post by 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!...
-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 (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? Considering that the
escape character should NOT be added to the resulting string, is there any
way I can avoid using the Maybe monad?
Once again, thanks everyone for all the suggestions!
Jean-Nicolas Jolivet
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
do something with my_string[i]
else
do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
Ozgur Akgun
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
mac
Ozgur Akgun
2010-04-29 20:37:42 UTC
Permalink
ok then,

foo ('=':'=':x:xs) = foo ('=':x:xs)
foo ('=':x:xs) = chr (ord x - 106) : foo xs
foo (x:xs) = chr (ord x - 42) : foo xs
foo _ = []
Post by matthew coolbeth
This works, except for the case where '=' appears more than twice
consecutively. A string of multiple '=' should be treated as a single '='.
Post by Ozgur Akgun
I won't attempt writing a general-case function now. If I understood your
(rather long) description correctly, you want to
- subtract 42 from the ascii value of the char, except when it is
preceeded by '=', in which case you subtract 106 instead.
foo :: [Char] -> [Char]
foo ('=':x:xs) = chr (ord x - 106) : foo xs
foo (x:xs) = chr (ord x - 42) : foo xs
foo _ = []
Hope I understood the problem correctly.
Best,
Post by 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!...
-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 (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? Considering that the
escape character should NOT be added to the resulting string, is there any
way I can avoid using the Maybe monad?
Once again, thanks everyone for all the suggestions!
Jean-Nicolas Jolivet
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
do something with my_string[i]
else
do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
Ozgur Akgun
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
mac
--
Ozgur Akgun
Jean-Nicolas Jolivet
2010-04-29 20:39:05 UTC
Permalink
Haha, sorry for the (rather long) description ;) The ending was really the important part :)

Basically I just wanted to explain the context of what I'm trying to do. Like I said, I already figured out a way to do all that... I'm just wondering if there is a better way to get to the final string result than building a list of Maybe Char and mapping it using mapMaybe...(considering that some characters of the initial string will NOT end up in the resulting string)...

Every solution I found was iterating to a list of character one character at a time, and outputting a character as a result (whether it is by recursion, mapping, etc..), however, what I was trying to explain in my previous post was that; when I am processing the escape character, this character should not be added to the resulting string... This is where I decided to use the Maybe monad..I'm just wondering if there is a better way...!


Jean-Nicolas Jolivet
I won't attempt writing a general-case function now. If I understood your (rather long) description correctly, you want to
- subtract 42 from the ascii value of the char, except when it is preceeded by '=', in which case you subtract 106 instead.
foo :: [Char] -> [Char]
foo ('=':x:xs) = chr (ord x - 106) : foo xs
foo (x:xs) = chr (ord x - 42) : foo xs
foo _ = []
Hope I understood the problem correctly.
Best,
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!...
-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 (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? Considering that the escape character should NOT be added to the resulting string, is there any way I can avoid using the Maybe monad?
Once again, thanks everyone for all the suggestions!
Jean-Nicolas Jolivet
Post by Jean-Nicolas Jolivet
Hi there!
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!
I'm totally new to Haskell so I'm pretty sure I'm missing something
obvious... I tried with list comprehensions...map... etc... but I
can't figure out how I can access the previous character in my string
in each "iteration".... to use simple pseudo code, what i need to do
do something with my_string[i]
else
do something else with my_string[i]
I'm using imperative programming here obviously since it's what I am
familiar with...but any help as to how I could "translate" this to
functional programming would be really appreciated!
Jean-Nicolas Jolivet
_______________________________________________
Beginners mailing list
http://www.haskell.org/mailman/listinfo/beginners
--
Ozgur Akgun
Stephen Tetley
2010-04-29 21:16:47 UTC
Permalink
On 29 April 2010 21:39, Jean-Nicolas Jolivet <***@gmail.com> wrote:

[Snip]
Post by Jean-Nicolas Jolivet
Every solution I found was iterating to a list of character one character at
a time, and outputting a character as a result (whether it is by recursion,
mapping, etc..), however, what I was trying to explain in my previous post
was that; when I am processing the escape character, this character should
not be added to the resulting string... This is where I decided to use the
Maybe monad..I'm just wondering if there is a better way...!
Hi Jean-Nicolas

The 'hand crafted lexer' style is quite common for this, with
different functions for different states (here body and escape).

I use a Hughes list as an explicit accumulator (a Hughes list is
sometimes called a difference list and familiar for strings as the
ShowS type synonym). This has more efficient right-addition (snoc)
than normal lists [a].
Post by Jean-Nicolas Jolivet
toString :: ShowS -> String
toString = ($ [])
snoc :: ShowS -> Char -> ShowS
snoc f a = f . (a:)
emptyH :: ShowS
emptyH = id
escape :: String -> ShowS -> ShowS
escape (_:xs) acc = body xs acc -- drop1, change state
escape _ acc = acc -- oh dear escape to the end-of-string
body :: String -> ShowS -> ShowS
body ('\\':xs) acc = escape xs acc -- change state
body (x:xs) acc = body xs (acc `snoc` x)
body _ acc = acc
run :: String -> String
run xs = toString (body xs emptyH)
demo1 = run "\\s1234" -- "1234"
Best wishes

Stephen
Daniel Fischer
2010-04-29 21:23:52 UTC
Permalink
Post by Jean-Nicolas Jolivet
Every solution I found was iterating to a list of character one
character at a time, and outputting a character as a result (whether it
is by recursion, mapping, etc..),
Well, that's necessary for what you want to do, isn't it?
Post by Jean-Nicolas Jolivet
however, what I was trying to explain
in my previous post was that; when I am processing the escape character,
this character should not be added to the resulting string... This is
where I decided to use the Maybe monad..I'm just wondering if there is a
better way...!
Depends on your criteria.
For raw performance, I think the directly coded recursion is a bit better

(btw,

fooGen e esc norm = go False
where
go b (x:xs)
| x == e = go True xs
| b = esc x : go False xs
| otherwise = norm x : go False xs
go _ [] = []
).

For code cleanliness, catMaybes&zipWith and a good directly coded recursion
are about equal.

For leetness, the foldr is beats them, but surely one could do much
'better'.
Daniel Fischer
2010-04-29 20:50:21 UTC
Permalink
Post by 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!...
-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.
Post by Jean-Nicolas Jolivet
(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.
Post by Jean-Nicolas Jolivet
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.
Post by Jean-Nicolas Jolivet
Once again, thanks everyone for all the suggestions!
Jean-Nicolas Jolivet
Jean-Nicolas Jolivet
2010-04-29 21:13:21 UTC
Permalink
Post by Daniel Fischer
-- assuming that only characters > 'i' (chr 105) are escaped (or the escape
character itself, but that should be dropped regardless).
Sorry, this is my fault for not being clearer about it: I am decoding text that is already encoded with a Binary to ASCII encoding... the exact encoding process is this:

1. Fetch a character from the input stream.
2. Increment the character's ASCII value by 42, modulo 256
3. If the result is a critical character ('\NUL', '\r', '\n' or '='), write the escape character ('=') to the output stream and increment character's ASCII value by 64, modulo 256.
4. Output the character to the output stream.

I am writing a decoder here so obviously I am reversing the process.... (I remove 42 for regular characters, 106 for special characters...and if the result is < 0, I add 256 to it...)

Just adding (yet again) more context information here ;) Still trying to fully understand your last suggestions Daniel! :) Thanks again!

Also, I wouldn't want anyone to think I just want someone to write the algorithm for me! :) Like I said, I already have a fully working algorithm, but being new to Haskell, I'm looking for ways to optimize it (or, really just different ways that I could do it!)

Here's how I am doing it right now (I am using ByteString here, but it should be pretty straightforward anyway)... I'm warning you, this is pretty ugly :)

-- Decode an encoded ByteString
-- the zip + tail method removes the first character so I am adding it afterward (ugly)
decodeByteString :: L.ByteString -> L.ByteString
decodeByteString str = do
let str1 = mapMaybe decodepair (L.zip str(L.tail str))
let firstChar = decodechar (ord(L.head str) - 42)
L.pack (firstChar:str1)

-- Decode a pair of character, returning either the
-- decoded character or Nothing
decodepair :: (Char, Char) -> Maybe Char
decodepair cs
| snd(cs) == '=' = Nothing
| fst(cs) == '=' = Just (decodechar(ord(snd cs) - 106))
| otherwise = Just (decodechar(ord(snd cs) - 42))

-- Reverse the modulo 256...
decodechar :: Int -> Char
decodechar i
| i < 0 = chr (i + 256)
| otherwise = chr i




Jean-Nicolas Jolivet
Post by Daniel Fischer
Post by 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!...
-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.
Post by Jean-Nicolas Jolivet
(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.
Post by Jean-Nicolas Jolivet
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.
Post by Jean-Nicolas Jolivet
Once again, thanks everyone for all the suggestions!
Jean-Nicolas Jolivet
Daniel Fischer
2010-04-29 23:27:54 UTC
Permalink
Post by Jean-Nicolas Jolivet
Post by Daniel Fischer
-- assuming that only characters > 'i' (chr 105) are escaped (or the
escape character itself, but that should be dropped regardless).
Sorry, this is my fault for not being clearer about it: I am decoding
text that is already encoded with a Binary to ASCII encoding... the
1. Fetch a character from the input stream.
2. Increment the character's ASCII value by 42, modulo 256
3. If the result is a critical character ('\NUL', '\r', '\n' or '='),
write the escape character ('=') to the output stream and increment
character's ASCII value by 64, modulo 256. 4. Output the character to
the output stream.
Okay, so there are no two escape characters in succession.
Post by Jean-Nicolas Jolivet
I am writing a decoder here so obviously I am reversing the process....
(I remove 42 for regular characters, 106 for special characters...and if
the result is < 0, I add 256 to it...)
Just adding (yet again) more context information here ;) Still trying to
fully understand your last suggestions Daniel! :) Thanks again!
Also, I wouldn't want anyone to think I just want someone to write the
algorithm for me! :) Like I said, I already have a fully working
algorithm, but being new to Haskell, I'm looking for ways to optimize it
(or, really just different ways that I could do it!)
Here's how I am doing it right now (I am using ByteString here,
Then the foldr is not the best option.
Post by Jean-Nicolas Jolivet
but it should be pretty straightforward anyway)...
I'm warning you, this is pretty ugly :)
-- Decode an encoded ByteString
-- the zip + tail method removes the first character so I am adding it afterward (ugly)
decodeByteString :: L.ByteString -> L.ByteString
decodeByteString str = do
let str1 = mapMaybe decodepair (L.zip str(L.tail str))
let firstChar = decodechar (ord(L.head str) - 42)
L.pack (firstChar:str1)
Is it really necessary to pack it? That's a relatively expensive operation,
it may be better to have it return a String if you're not doing anything
with it after decoding except writing it to a file or so.

The zipping is also not the optimal choice, it takes a lot of checking for
the chunk-boundaries (I assume you're using lazy ByteStrings, since you
chose the prefix L), and you construct pairs only to deconstruct them
immediately (the compiler *may* optimise them away, but I'm skeptical).
Post by Jean-Nicolas Jolivet
-- Decode a pair of character, returning either the
-- decoded character or Nothing
decodepair :: (Char, Char) -> Maybe Char
decodepair cs
| snd(cs) == '=' = Nothing
| fst(cs) == '=' = Just (decodechar(ord(snd cs) - 106))
| otherwise = Just (decodechar(ord(snd cs) - 42))
-- Reverse the modulo 256...
decodechar :: Int -> Char
decodechar i
| i < 0 = chr (i + 256)
| otherwise = chr i
Since you're doing arithmetic modulo 256, that stuff can be done faster and
simpler with Word8.

----------------------------------------------------------------------
{-# LANGUAGE BangPatterns #-}

import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as S
import Data.ByteString.Unsafe (unsafeAt)

escape :: Word8 -> Word8
escape = (+150)

normal :: Word8 -> Word8
normal = (+214)

decodeW :: L.ByteString -> [Word8]
decodeW = dec False . L.toChunks
where
dec _ [] = []
dec esc (str:more) = go esc 0
where
!len = S.length str
{-# INLINE charAt #-}
charAt :: Int -> Word8
charAt i = unsafeAt str i
go !b !i
| i == len = dec b more
| b = escape (charAt i) : go False (i+1)
| otherwise = case charAt i of
61 -> go True (i+1)
c -> normal c : go False (i+1)

word8ToChar :: Word8 -> Char
word8ToChar = toEnum . fromIntegral

decodeC :: L.ByteString -> String
decodeC = map word8ToChar . decodeW

decodeBS :: L.ByteString -> L.ByteString
decodeBS = L.pack . decodeW
----------------------------------------------------------------------
Post by Jean-Nicolas Jolivet
Jean-Nicolas Jolivet
Post by Daniel Fischer
Post by 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!...
-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.
Post by Jean-Nicolas Jolivet
(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.
Post by Jean-Nicolas Jolivet
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.
Post by Jean-Nicolas Jolivet
Once again, thanks everyone for all the suggestions!
Jean-Nicolas Jolivet
Daniel Fischer
2010-04-30 00:32:35 UTC
Permalink
Post by Daniel Fischer
----------------------------------------------------------------------
{-# LANGUAGE BangPatterns #-}
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString as S
import Data.ByteString.Unsafe (unsafeAt)
Oops,

import Data.ByteString.Unsafe (unsafeIndex)
Post by Daniel Fischer
escape :: Word8 -> Word8
escape = (+150)
normal :: Word8 -> Word8
normal = (+214)
decodeW :: L.ByteString -> [Word8]
decodeW = dec False . L.toChunks
    where
      dec _ [] = []
      dec esc (str:more) = go esc 0
        where
          !len = S.length str
          {-# INLINE charAt #-}
          charAt :: Int -> Word8
          charAt i = unsafeAt str i
charAt i = unsafeIndex str i
Post by Daniel Fischer
          go !b !i
            | i == len  = dec b more
            | b         = escape (charAt i) : go False (i+1)
            | otherwise = case charAt i of
                            61 -> go True (i+1)
                            c  -> normal c : go False (i+1)
word8ToChar :: Word8 -> Char
word8ToChar = toEnum . fromIntegral
decodeC :: L.ByteString -> String
decodeC = map word8ToChar . decodeW
decodeBS :: L.ByteString -> L.ByteString
decodeBS = L.pack . decodeW
----------------------------------------------------------------------
Daniel Fischer
2010-04-30 01:20:39 UTC
Permalink
Sorry to bug you again :\
I'm getting the following when trying to run it this time...Absolutely
no idea why!
Not in scope: type constructor or class `Word8'
I forgot

import Data.Word (Word8)

:(
(I replied to you directly since I didn't want to make the already-large
thread on the mailing list even larger ;)
I do :)
Jean-Nicolas
"Module `Data.ByteString.Unsafe' does not export `unsafeAt'"
Yes, of course. It's "unsafeIndex" (unsafeAt is for arrays), d'oh.
(Using the latest ghc...
http://www.haskell.org/ghc/docs/latest/html/libraries/bytestring-0.9.
1.6 /Data-ByteString-Unsafe.html )
Jean-Nicolas Jolivet
Continue reading on narkive:
Loading...