Separate a string into a list of strings

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
39 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Separate a string into a list of strings

Sara Kenedy
Hi all,

I want to write a function to separate a string into a list of strings
separated by commas.

Example:
separate :: String -> [String]

separate "Haskell, Haskell, and Haskell" = ["Haskell", "Haskell", "and Haskell"]

If anyone has some ideas, please share with me. Thanks.

S.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Separate a string into a list of strings

J. Garrett Morris
Off the top of my head:

separate :: String -> [String]
separate [] = []
separate s =
  case break (',' ==) s of
    (s,[]) -> [s]
    (s,',':s') -> s : separate s'
    _ -> error "how did we get here?"

There is at least one cunning rewriting with foldl, I think, but I
think this version is clearer.

 /g

On 6/12/06, Sara Kenedy <[hidden email]> wrote:

> Hi all,
>
> I want to write a function to separate a string into a list of strings
> separated by commas.
>
> Example:
> separate :: String -> [String]
>
> separate "Haskell, Haskell, and Haskell" = ["Haskell", "Haskell", "and Haskell"]
>
> If anyone has some ideas, please share with me. Thanks.
>
> S.
> _______________________________________________
> Haskell-Cafe mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>


--
We have lingered in the chambers of the sea
By sea-girls wreathed with seaweed red and brown
Till human voices wake us, and we drown.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Separate a string into a list of strings

Neil Mitchell
In reply to this post by Sara Kenedy
Hi,

I tend to use the module TextUtil (or Util.Text) from Yhc for these
kind of string manipulations:

http://www-users.cs.york.ac.uk/~malcolm/cgi-bin/darcsweb.cgi?r=yhc;a=headblob;f=/src/compiler98/Util/Text.hs

separate = splitList ","

I am currently thinking about making this module into a standalone
library with some other useful functions, if people have any opinions
on this then please let me know.

Thanks

Neil


On 6/12/06, Sara Kenedy <[hidden email]> wrote:

> Hi all,
>
> I want to write a function to separate a string into a list of strings
> separated by commas.
>
> Example:
> separate :: String -> [String]
>
> separate "Haskell, Haskell, and Haskell" = ["Haskell", "Haskell", "and Haskell"]
>
> If anyone has some ideas, please share with me. Thanks.
>
> S.
> _______________________________________________
> Haskell-Cafe mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Separate a string into a list of strings

Clifford Beshers
In reply to this post by Sara Kenedy
Sara Kenedy wrote:
Hi all,

I want to write a function to separate a string into a list of strings
separated by commas.

Example:
separate :: String -> [String]

separate "Haskell, Haskell, and Haskell" = ["Haskell", "Haskell", "and Haskell"]

If anyone has some ideas, please share with me. Thanks.
Here is a solution using the Posix regex module.
Prelude Text.Regex> splitRegex (mkRegex "[ \t]*,[ \t]*") "Haskell, Haskell, and Haskell"
["Haskell","Haskell","and Haskell"]
This form should work regardless of locale, but appears to be broken, although I expect this is either my fault or that of the underlying Posix library:
Prelude Text.Regex> splitRegex (mkRegex "[:space:]*,[:space:]*") "Haskell, Haskell, and Haskell"
["Haskell"," Haskell"," and Haskell"]


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Separate a string into a list of strings

Brandon Moore
Clifford Beshers wrote:

> Sara Kenedy wrote:
>
>> Hi all,
>>
>> I want to write a function to separate a string into a list of strings
>> separated by commas.
>>
>> Example:
>> separate :: String -> [String]
>>
>> separate "Haskell, Haskell, and Haskell" = ["Haskell", "Haskell", "and
>> Haskell"]
>>
>> If anyone has some ideas, please share with me. Thanks.
>
> Here is a solution using the Posix regex module.
>
>     Prelude Text.Regex> splitRegex (mkRegex "[ \t]*,[ \t]*") "Haskell,
>     Haskell, and Haskell"
>     ["Haskell","Haskell","and Haskell"]
>
> This form should work regardless of locale, but appears to be broken,
> although I expect this is either my fault or that of the underlying
> Posix library:
>
>     Prelude Text.Regex> splitRegex (mkRegex "[:space:]*,[:space:]*")
>     "Haskell, Haskell, and Haskell"
>     ["Haskell"," Haskell"," and Haskell"]

Going by man grep, those [:foo:] classes are only special inside a
character class, otherwise [:space:]* = [aceps:]*.

   Prelude Text.Regex> splitRegex (mkRegex "[[:space:]]*,[[:space:]]*")
   "Haskell, Haskell, and Haskell"
   ["Haskell","Haskell","and Haskell"]

Brandon
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Separate a string into a list of strings

Jared Updike
In reply to this post by Neil Mitchell
Funny. I have a module called Useful.hs with some of these same sorts
of functions. (coming from Python where I used .split(',') and
.replace('\r', '') and such a lot):

------------------
module Useful where

import List ( intersperse, tails )
import Numeric ( readHex )

hex2num :: (Num a) => String -> a
hex2num s = let (result, _):_ = readHex s in result

toEnv s = map tuple (split ';' s)

tuple :: String -> (String, String)
tuple line = case split '=' line of
   a:b:_ -> (a,b)
   a:_   -> (a,"")
   _     -> ("","") -- not good, probably won't happen for my typical usage...

split       :: Char -> String -> [String]
split _ ""  =  []
split c s   =  let (l, s') = break (== c) s
                 in  l : case s' of
                           []      -> []
                           (_:s'') -> split c s''

beginsWith []       []     = True
beginsWith _        []     = True
beginsWith []       _      = False
beginsWith (a:aa)   (b:bb)
    | a == b               = aa `beginsWith` bb
    | otherwise            = False

dropping []     []     = []
dropping []     _      = []
dropping x      []     = x
dropping s@(a:aa) (b:bb) | a == b    = dropping aa bb
                         | otherwise = s

-- replace all occurrences of 'this' with 'that' in the string 'str'
-- like Python replace
replace _    _    []  = []
replace this that str
    | str `beginsWith` this = let after = (str `dropping` this)
                               in  that ++ replace this that after
    | otherwise             =
        let x:xs = str
          in x : replace this that xs

eat s = replace s ""

-- sometimes newlines get out of hand on the end of form POST submissions,
-- so trim all the end newlines and add a single newline
fixEndingNewlines = reverse . ('\n':) . dropWhile (=='\n') . reverse .
filter (/= '\r')

endsWith a b = beginsWith (reverse a) (reverse b)

a `contains` b = any (`beginsWith` b) $ tails a
------------------

  Jared.

On 6/12/06, Neil Mitchell <[hidden email]> wrote:

> Hi,
>
> I tend to use the module TextUtil (or Util.Text) from Yhc for these
> kind of string manipulations:
>
> http://www-users.cs.york.ac.uk/~malcolm/cgi-bin/darcsweb.cgi?r=yhc;a=headblob;f=/src/compiler98/Util/Text.hs
>
> separate = splitList ","
>
> I am currently thinking about making this module into a standalone
> library with some other useful functions, if people have any opinions
> on this then please let me know.
>
> Thanks
>
> Neil
>
>
> On 6/12/06, Sara Kenedy <[hidden email]> wrote:
> > Hi all,
> >
> > I want to write a function to separate a string into a list of strings
> > separated by commas.
> >
> > Example:
> > separate :: String -> [String]
> >
> > separate "Haskell, Haskell, and Haskell" = ["Haskell", "Haskell", "and Haskell"]
> >
> > If anyone has some ideas, please share with me. Thanks.
> >
> > S.
> > _______________________________________________
> > Haskell-Cafe mailing list
> > [hidden email]
> > http://www.haskell.org/mailman/listinfo/haskell-cafe
> >
> _______________________________________________
> Haskell-Cafe mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>


--
http://www.updike.org/~jared/
reverse ")-:"
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Separate a string into a list of strings

Neil Mitchell
Hi

> beginsWith []       []     = True
> beginsWith _        []     = True
> beginsWith []       _      = False
> beginsWith (a:aa)   (b:bb)
>     | a == b               = aa `beginsWith` bb
>     | otherwise            = False

I used to have this in my library then I discovered isPrefixOf :) (or
flip isPrefixOf, I think in this case)

> endsWith a b = beginsWith (reverse a) (reverse b)
ditto, isSuffixOf

Thanks

Neil
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Separate a string into a list of strings

Clifford Beshers
In reply to this post by Brandon Moore
Brandon Moore wrote:
>
> Going by man grep, those [:foo:] classes are only special inside a
> character class, otherwise [:space:]* = [aceps:]*.
>
>   Prelude Text.Regex> splitRegex (mkRegex "[[:space:]]*,[[:space:]]*")
>   "Haskell, Haskell, and Haskell"
>   ["Haskell","Haskell","and Haskell"]

The smart money was on user error.   Thanks.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re[2]: Separate a string into a list of strings

Bulat Ziganshin-2
In reply to this post by Neil Mitchell
Hello Neil,

Tuesday, June 13, 2006, 2:55:42 AM, you wrote:

> I tend to use the module TextUtil (or Util.Text) from Yhc for these
> kind of string manipulations:
> I am currently thinking about making this module into a standalone
> library with some other useful functions, if people have any opinions
> on this then please let me know.

having good Strings library is a MUST. it required everyday and every
large enough program contains such internal modules. moreover, such
module is absolute need to write scripts in Haskell, and i think it
should be included in std hierarchical libs. i already had the idea of
starting such module so if you can do public repository for it - it
will be even better

--
Best regards,
 Bulat                            mailto:[hidden email]

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Separate a string into a list of strings

Clifford Beshers
In reply to this post by J. Garrett Morris
Well, I couldn't resist the puzzle.  Here are solutions using foldr and
unfoldr.  Don't know if they are cunning or not, but they were kind of fun.

import Data.List

splitByElem e xs =
    unfoldr f xs
    where f s =
          case break (e ==) s of
            ("",_) -> Nothing
            (a,b) -> Just (a, drop 1 b)


splitByElem1 e xs =
    foldr f [[]] xs
    where f a b = if a == e then [] : b else (a : head b) : (tail b)



J. Garrett Morris wrote:

>
> There is at least one cunning rewriting with foldl, I think, but I
> think this version is clearer.
>
> /g
>
> On 6/12/06, Sara Kenedy <[hidden email]> wrote:
>> Hi all,
>>
>> I want to write a function to separate a string into a list of strings
>> separated by commas.
>>
>> Example:
>> separate :: String -> [String]
>>
>> separate "Haskell, Haskell, and Haskell" = ["Haskell", "Haskell",
>> "and Haskell"]
>>
>> If anyone has some ideas, please share with me. Thanks.
>>
>> S.
>> _______________________________________________
>> Haskell-Cafe mailing list
>> [hidden email]
>> http://www.haskell.org/mailman/listinfo/haskell-cafe
>>
>
>

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Separate a string into a list of strings

Donn Cave-2
In reply to this post by Sara Kenedy
Quoth Clifford Beshers <[hidden email]>:
| Well, I couldn't resist the puzzle.  Here are solutions using foldr and
| unfoldr.  Don't know if they are cunning or not, but they were kind of fun.

...
| splitByElem1 e xs =
|     foldr f [[]] xs
|     where f a b = if a == e then [] : b else (a : head b) : (tail b)

This does the right thing with trailing separators, which is not to be
taken for granted among Haskell split implementations.  The splits I have
been seeing in this thread are conservative, so if the separator is ':',
then "::a" splits to ["", "", "a"].  Frequently however the implementation
fails to deal with the trailing separator, so "a:" is ["a"], where it
should be ["a", ""].  It's not something you run into right away.

In a liberal split, "a " should indeed be ["a"], but that's a different
matter.  Neither of the two I've looked at seems to be shooting for a
liberal "words" white space split.

        Donn
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Separate a string into a list of strings

Clifford Beshers
Donn Cave wrote:

> Quoth Clifford Beshers <[hidden email]>:
> | Well, I couldn't resist the puzzle.  Here are solutions using foldr and
> | unfoldr.  Don't know if they are cunning or not, but they were kind of fun.
>
> ...
> | splitByElem1 e xs =
> |     foldr f [[]] xs
> |     where f a b = if a == e then [] : b else (a : head b) : (tail b)
>
> This does the right thing with trailing separators, which is not to be
> taken for granted among Haskell split implementations.  The splits I have
> been seeing in this thread are conservative, so if the separator is ':',
> then "::a" splits to ["", "", "a"].  Frequently however the implementation
> fails to deal with the trailing separator, so "a:" is ["a"], where it
> should be ["a", ""].  It's not something you run into right away.
>
> In a liberal split, "a " should indeed be ["a"], but that's a different
> matter.  Neither of the two I've looked at seems to be shooting for a
> liberal "words" white space split.
Good point.  My solutions are inconsistent on white space, which I don't
like.

Your criterion eliminates this solution as well:

filter (/= ",") $ groupBy (\x y -> x /= ',' && y /= ',') "Haskell,
Haskell, and Haskell,"
["Haskell"," Haskell"," and Haskell"]

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Separate a string into a list of strings

Ketil Malde-3
In reply to this post by Jared Updike
"Jared Updike" <[hidden email]> writes:

> On 6/12/06, Neil Mitchell <[hidden email]> wrote:

>> I tend to use the module TextUtil (or Util.Text) from Yhc for these
>> kind of string manipulations:

> Funny. I have a module called Useful.hs with some of these same sorts
> of functions. (coming from Python where I used .split(',') and
> .replace('\r', '') and such a lot):

Clifford Beshers writes:

> Here is a solution using the Posix regex module.

In addition, there are similar things in John Goerzen's MissingH, and
in FPS.  It'd be nice if the Data.List interface included these.
Seems there is a two-d matrix, one is the split criterion (matching
element, number of elements, boolean function on elements), the other
is the return type (split off one (-> ([a],[a])) or split up the whole
string (-> [[a]])).  Arbitrarily┬╣ naming the former 'split' and
the latter 'break', you could have something like:

split :: a -> [a] -> ([a],[a])
splitAt :: Int -> [a] -> ([a],[a])
splitWhen :: (a -> Bool) -> [a] -> ([a],[a])

break :: a -> [a] -> [[a]]
breakAt :: Int -> [a] -> [[a]]
breakWhen :: (a -> Bool) -> [a] -> [[a]]

-k

┬╣ Well, perhaps not quite, it seems more natural to me to 'split in
two' and 'break into pieces'.
--
If I haven't seen further, it is by standing in the footprints of giants

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Embedding newlines into a string? [Was: Re: Separate a string into a list of strings]

Benjamin L. Russell
In reply to this post by Jared Updike
A friend and I were working on a Haskell version of
Towers of Hanoi yesterday, and I tried writing out the
program today, but got stuck on outputting newlines as
part of the string; viz:

hanoi :: Int -> String
hanoi n = hanoi_helper 'a' 'b' 'c' n
         
hanoi_helper :: Char -> Char -> Char -> Int -> String
hanoi_helper source using dest n
    | n == 1 = putStrLn "Move " ++ show source ++ " to
" ++ show dest ++ "." ++ show '\n'
    | otherwise = hanoi_helper source dest using (n-1)

                  ++ hanoi_helper source using dest 1
                         ++ hanoi_helper using source
dest (n-1)

The problem is that the newlines ('\n') get embedded
as escaped newlines into the output string, instead of
as newlines.

E.g.,

Hugs> :load hanoi.hs
Main> hanoi 2
"Move 'a' to 'b'.'\\n'Move 'a' to 'c'.'\\n'Move 'b' to
'c'.'\\n'"

Instead, what I want is the following:

Hugs> :load hanoi.hs
Main> hanoi 2
"Move 'a' to 'b'.
Move 'a' to 'c'.
Move 'b' to 'c'.
"

However, when I try to use putStrLn to avoid this
problem, as follows:

    | n == 1 = putStrLn "Move " ++ show source ++ " to
" ++ show dest ++ "." ++ show '\n'

the compiler generates the following error:

ERROR file:hanoi.hs:6 - Type error in application
*** Expression     : putStrLn "Move " ++ show source
++ " to " ++ show dest ++ "." ++ show '\n'
*** Term           : putStrLn "Move "
*** Type           : IO ()
*** Does not match : [Char]

Simply changing the type signature does not solve this
problem.

I searched through the past messages on this list, and
came up with the message below, but simply quoting the
newlines as '\n' doesn't seem to help.

Does anybody know a way to embed a newline into a
string as output of type String of a function so that
the newline characters are not escaped?

Benjamin L. Russell

--- Jared Updike <[hidden email]> wrote:

> Funny. I have a module called Useful.hs with some of
> these same sorts
> of functions. (coming from Python where I used
> .split(',') and
> .replace('\r', '') and such a lot):
>
> ------------------
> module Useful where
>
> import List ( intersperse, tails )
> import Numeric ( readHex )
>
> hex2num :: (Num a) => String -> a
> hex2num s = let (result, _):_ = readHex s in result
>
> toEnv s = map tuple (split ';' s)
>
> tuple :: String -> (String, String)
> tuple line = case split '=' line of
>    a:b:_ -> (a,b)
>    a:_   -> (a,"")
>    _     -> ("","") -- not good, probably won't
> happen for my typical usage...
>
> split       :: Char -> String -> [String]
> split _ ""  =  []
> split c s   =  let (l, s') = break (== c) s
>                  in  l : case s' of
>                            []      -> []
>                            (_:s'') -> split c s''
>
> beginsWith []       []     = True
> beginsWith _        []     = True
> beginsWith []       _      = False
> beginsWith (a:aa)   (b:bb)
>     | a == b               = aa `beginsWith` bb
>     | otherwise            = False
>
> dropping []     []     = []
> dropping []     _      = []
> dropping x      []     = x
> dropping s@(a:aa) (b:bb) | a == b    = dropping aa
> bb
>                          | otherwise = s
>
> -- replace all occurrences of 'this' with 'that' in
> the string 'str'
> -- like Python replace
> replace _    _    []  = []
> replace this that str
>     | str `beginsWith` this = let after = (str
> `dropping` this)
>                                in  that ++ replace
> this that after
>     | otherwise             =
>         let x:xs = str
>           in x : replace this that xs
>
> eat s = replace s ""
>
> -- sometimes newlines get out of hand on the end of
> form POST submissions,
> -- so trim all the end newlines and add a single
> newline
> fixEndingNewlines = reverse . ('\n':) . dropWhile
> (=='\n') . reverse .
> filter (/= '\r')
>
> endsWith a b = beginsWith (reverse a) (reverse b)
>
> a `contains` b = any (`beginsWith` b) $ tails a
> ------------------
>
>   Jared.
>
> On 6/12/06, Neil Mitchell <[hidden email]>
> wrote:
> > Hi,
> >
> > I tend to use the module TextUtil (or Util.Text)
> from Yhc for these
> > kind of string manipulations:
> >
> >
>
http://www-users.cs.york.ac.uk/~malcolm/cgi-bin/darcsweb.cgi?r=yhc;a=headblob;f=/src/compiler98/Util/Text.hs

> >
> > separate = splitList ","
> >
> > I am currently thinking about making this module
> into a standalone
> > library with some other useful functions, if
> people have any opinions
> > on this then please let me know.
> >
> > Thanks
> >
> > Neil
> >
> >
> > On 6/12/06, Sara Kenedy <[hidden email]>
> wrote:
> > > Hi all,
> > >
> > > I want to write a function to separate a string
> into a list of strings
> > > separated by commas.
> > >
> > > Example:
> > > separate :: String -> [String]
> > >
> > > separate "Haskell, Haskell, and Haskell" =
> ["Haskell", "Haskell", "and Haskell"]
> > >
> > > If anyone has some ideas, please share with me.
> Thanks.
> > >
> > > S.
> > > _______________________________________________
> > > Haskell-Cafe mailing list
> > > [hidden email]
> > >
> http://www.haskell.org/mailman/listinfo/haskell-cafe
> > >
> > _______________________________________________
> > Haskell-Cafe mailing list
> > [hidden email]
> >
> http://www.haskell.org/mailman/listinfo/haskell-cafe
> >
>
>
> --
> http://www.updike.org/~jared/
> reverse ")-:"
> _______________________________________________
> Haskell-Cafe mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Embedding newlines into a string? [Was: Re: Separate a string into a list of strings]

Neil Mitchell
Hi



On Mon, Apr 14, 2008 at 8:22 AM, Benjamin L. Russell
<[hidden email]> wrote:
> A friend and I were working on a Haskell version of
>  Towers of Hanoi yesterday, and I tried writing out the
>  program today, but got stuck on outputting newlines as
>  part of the string; viz:

>     | n == 1 = putStrLn ("Move " ++ show source ++ " to
>  " ++ show dest ++ "." ++ show '\n')

show '\n' = "\\n"

"\n" == "\n"

Therefore:

>     | n == 1 = putStrLn ("Move " ++ show source ++ " to
>  " ++ show dest ++ "." ++ "\n")

Note that you need the brackets, an in general don't call show on a
String or a Char.

Thanks

Neil
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Embedding newlines into a string?

Tillmann Rendel-2
In reply to this post by Benjamin L. Russell
Benjamin L. Russell wrote:
> but got stuck on outputting newlines as part of the string;

quoting is done by the show function in Haskell, so you have to take
care to avoid calling show. your code calls show at two positions:
(1) when you insert the newline into the string
(2) when you output the string

with respect to (1):

you use (show '\n') to create a newline-only string, which produces a
machine-readable (!) textual representation of '\n'. try the difference
between

   > '\n'

and

   > show '\n'

to see what I mean. instead of using (show '\n'), you should simply use
"\n" to encode the string of length 1 containing a newline character.

with respect to (2):

the type of your top-level expression is String, which is automatically
print'ed by the interpreter. but print x = putStrLn (show x), so there
is another call to show at this point. to avoid this call, write an IO
action yourself. try the difference between

   putStrLn (hanoi ...)

and

   print (hanoi ...)

to see what I mean.

Last, but not least, I would like to point out a different aproach to
multiline output which is often used by Haskell programmers: The worker
functions in this aproach produces a list of strings, which is joined
together with newlines by the unlines function. In your case:

   hanoi_helper :: ... -> [String]
     | ... = ["Move " ++ ...]
     | otherwise = hanoi_helper ... ++ hanoi_helper ...

   hanoi n = hanoi_helper 'a' 'b' 'c' n

and in the interpreter one of these:

   > hanoi 2 -- outputs a list
   > mapM_ putStrLn (hanoi 2) -- outputs each move in a new line
   > putStrLn (unlines (hanoi 2)) -- same as previous line

Tillmann
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Re: Embedding newlines into a string?

Benjamin L. Russell
Ok; much better.  Here's my new type signature and
definition:

hanoi.hs:
hanoi :: Int -> IO ()
hanoi n = mapM_ putStrLn (hanoi_helper 'a' 'b' 'c' n)
         
hanoi_helper :: Char -> Char -> Char -> Int ->
[String]
hanoi_helper source using dest n
    | n == 1 = ["Move " ++ show source ++ " to " ++
show dest ++ "."]
    | otherwise = hanoi_helper source dest using (n-1)

                  ++ hanoi_helper source using dest 1
                         ++ hanoi_helper using source
dest (n-1)

Then in WinHugs (Version Sep 2006):

Hugs> :load hanoi.hs
Main> hanoi 2
Move 'a' to 'b'.
Move 'a' to 'c'.
Move 'b' to 'c'.

Great!

One minor question:  I tried out both of your
following suggestions:

>    > mapM_ putStrLn (hanoi 2) -- outputs each move
> in a new line
>    > putStrLn (unlines (hanoi 2)) -- same as
> previous line

and discovered that putStrLn with unlines (the lower
option) in fact generates one extra blank line at the
end.  Just curious as to why....

Benjamin L. Russell

--- Tillmann Rendel <[hidden email]> wrote:

> Benjamin L. Russell wrote:
> > but got stuck on outputting newlines as part of
> the string;
>
> quoting is done by the show function in Haskell, so
> you have to take
> care to avoid calling show. your code calls show at
> two positions:
> (1) when you insert the newline into the string
> (2) when you output the string
>
> with respect to (1):
>
> you use (show '\n') to create a newline-only string,
> which produces a
> machine-readable (!) textual representation of '\n'.
> try the difference
> between
>
>    > '\n'
>
> and
>
>    > show '\n'
>
> to see what I mean. instead of using (show '\n'),
> you should simply use
> "\n" to encode the string of length 1 containing a
> newline character.
>
> with respect to (2):
>
> the type of your top-level expression is String,
> which is automatically
> print'ed by the interpreter. but print x = putStrLn
> (show x), so there
> is another call to show at this point. to avoid this
> call, write an IO
> action yourself. try the difference between
>
>    putStrLn (hanoi ...)
>
> and
>
>    print (hanoi ...)
>
> to see what I mean.
>
> Last, but not least, I would like to point out a
> different aproach to
> multiline output which is often used by Haskell
> programmers: The worker
> functions in this aproach produces a list of
> strings, which is joined
> together with newlines by the unlines function. In
> your case:
>
>    hanoi_helper :: ... -> [String]
>      | ... = ["Move " ++ ...]
>      | otherwise = hanoi_helper ... ++ hanoi_helper
> ...
>
>    hanoi n = hanoi_helper 'a' 'b' 'c' n
>
> and in the interpreter one of these:
>
>    > hanoi 2 -- outputs a list
>    > mapM_ putStrLn (hanoi 2) -- outputs each move
> in a new line
>    > putStrLn (unlines (hanoi 2)) -- same as
> previous line
>
> Tillmann
> _______________________________________________
> Haskell-Cafe mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Re: Embedding newlines into a string?

Neil Mitchell
Hi

>  >    > mapM_ putStrLn (hanoi 2) -- outputs each move
>  > in a new line
>  >    > putStrLn (unlines (hanoi 2)) -- same as
>  > previous line

putStr (unlines (hanoi 2))

is what you want. Unlines puts a trailing new line at the end of every
line, including the final one. putStrLn puts an additional trailing
new line, so you get 2 at the end.

mapM_ putStrLn == putStr . unlines

Thanks

Neil
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Re: Embedding newlines into a string?

Tillmann Rendel-2
Neil Mitchell wrote:
> Unlines puts a trailing new line at the end of every
> line, including the final one. putStrLn puts an additional trailing
> new line, so you get 2 at the end.

Thanks for that clarification.

> mapM_ putStrLn == putStr . unlines

I'm wondering which (==) you mean here ;)

   Tillmann
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Re: Embedding newlines into a string?

Neil Mitchell
Hi

> > mapM_ putStrLn == putStr . unlines
> >
>
>  I'm wondering which (==) you mean here ;)

Expression equality, defined by:

instance (Arbitrary a, Eq b) => Eq (a -> b) where
    f == g = forall x :: a, f x == g x

Using QuickCheck to generate the values, and an Eq over IO (), which
can be defined using the IO test modelling thing at last years Haskell
Workshop.

There are answers to all these things, even if Haskell can't express
all of them quite like this :)

Thanks

Neil
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
12