How to print a string (lazily)

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

How to print a string (lazily)

Daniel Carrera-2
Hello,

I've been studying more Haskell and I've improved a lot. But I just hit
a small problem. I want to print all the elements of a linst (putStr).
I'd like to write something like this:

print_list [] = do putStr ""
print_list (x:xs) = (do putStr x) && print_list xs

I know this is wrong, but I hope you can see what I'm trying to do.

I know of other ways I could print a list. For example:

print_list xs = do putStr(join xs)
        where join [] = ""
              join (x:xs) = (show x) ++ "\n" ++ join xs

But the thing is, I want to write a lazy version of this function. It's
not that I need such a function, I'm just trying to learn Haskell.

Any suggestions?

Question: What do you call a function that has side-effects? (like
putStr) I know that "function" is the wrong term.

Cheers,
Daniel.
--
      /\/`) http://oooauthors.org
     /\/_/  http://opendocumentfellowship.org
    /\/_/
    \/_/    I am not over-weight, I am under-tall.
    /
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to print a string (lazily)

Christian Maeder
Daniel Carrera wrote:
> print_list xs = do putStr(join xs)
>     where join [] = ""
>           join (x:xs) = (show x) ++ "\n" ++ join xs

print_list xs = mapM putStrLn xs

> Question: What do you call a function that has side-effects? (like
> putStr) I know that "function" is the wrong term.

"action", "command", "program", etc.

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

Re: How to print a string (lazily)

Adrian Hey
On Tuesday 03 Jan 2006 5:37 pm, Christian Maeder wrote:
> Daniel Carrera wrote:
>
> > Question: What do you call a function that has side-effects? (like
> > putStr) I know that "function" is the wrong term.
>
> "action", "command", "program", etc.

Actually (at the risk of appearing pedantic), I think it's important
to make clear that "function" *is* the correct term for putStr..
 putStr :: String -> IO ()
It's expressions like (putStr "Hello World") of type IO <something>
that are (what I would call) "actions".

Haskell has no name for "functions that have side-effects".
They don't exist (well not unless you're grossly abusing
unsafePerformIO).

Regards
--
Adrian Hey



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

Re: How to print a string (lazily)

haskell-2
In reply to this post by Daniel Carrera-2
Daniel Carrera wrote:

> Hello,
>
> I've been studying more Haskell and I've improved a lot. But I just hit
> a small problem. I want to print all the elements of a linst (putStr).
> I'd like to write something like this:
>
> print_list [] = do putStr ""
> print_list (x:xs) = (do putStr x) && print_list xs
>
> I know this is wrong, but I hope you can see what I'm trying to do.
>
> I know of other ways I could print a list. For example:
>
> print_list xs = do putStr(join xs)
>     where join [] = ""
>           join (x:xs) = (show x) ++ "\n" ++ join xs
>
> But the thing is, I want to write a lazy version of this function. It's
> not that I need such a function, I'm just trying to learn Haskell.
>
> Any suggestions?
>
> Question: What do you call a function that has side-effects? (like
> putStr) I know that "function" is the wrong term.
>
> Cheers,
> Daniel.

I sometimes call a function with side-effects in IO a "command".  But
the terms are fungible.  But calling putStr a "function" is correct.  It
is not a "pure function" however.

What does lazy printing mean?

I assume it means you evaluate the head of the list, print it, then
recursively do this for the tail of the list.  With an infinite list you
will get inifinite output.

I assume it does not mean you evaluate the whole list before printing
anything.  This would prevent infinite lists from producing output.

(mapM_ putStr) or (mapM_ putStrLn) will do what you want.

All of these commands show work, even if hw is inifitely long:

let printList [] = return ()
    printList (x:xs) = do putStrLn x
                          printList xs

main = do
  let hw = ["Hello"," ","World","!"]
  mapM_ putStr hw
  mapM_ putStrLn hw
  putStr (unlines hw) -- see also: unwords, words, lines
  printList hw

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

Re: How to print a string (lazily)

Neil Mitchell
In reply to this post by Daniel Carrera-2
Hi,

All Haskell functions are lazy, hence there is no need to "write a
lazy version" of your print_list function. I think the function you
probably want is:

putStr (unlines xs)

This uses the bulid in unlines function, which is similar in spirit to
join (you get more quotes, which I guess you don't want)

The equivalent in monad'y programming is:

mapM putStrLn xs

The first one has fewer monads, so I prefer it, but take your pick :)

Thanks

Neil


On 1/3/06, Daniel Carrera <[hidden email]> wrote:

> Hello,
>
> I've been studying more Haskell and I've improved a lot. But I just hit
> a small problem. I want to print all the elements of a linst (putStr).
> I'd like to write something like this:
>
> print_list [] = do putStr ""
> print_list (x:xs) = (do putStr x) && print_list xs
>
> I know this is wrong, but I hope you can see what I'm trying to do.
>
> I know of other ways I could print a list. For example:
>
> print_list xs = do putStr(join xs)
>         where join [] = ""
>               join (x:xs) = (show x) ++ "\n" ++ join xs
>
> But the thing is, I want to write a lazy version of this function. It's
> not that I need such a function, I'm just trying to learn Haskell.
>
> Any suggestions?
>
> Question: What do you call a function that has side-effects? (like
> putStr) I know that "function" is the wrong term.
>
> Cheers,
> Daniel.
> --
>       /\/`) http://oooauthors.org
>      /\/_/  http://opendocumentfellowship.org
>     /\/_/
>     \/_/    I am not over-weight, I am under-tall.
>     /
> _______________________________________________
> 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: How to print a string (lazily)

Sebastian Sylvan
In reply to this post by Daniel Carrera-2
On 1/3/06, Daniel Carrera <[hidden email]> wrote:
> Hello,
>
> I've been studying more Haskell and I've improved a lot. But I just hit
> a small problem. I want to print all the elements of a linst (putStr).
> I'd like to write something like this:
>
> print_list [] = do putStr ""
> print_list (x:xs) = (do putStr x) && print_list xs
>

Others have already replied with a solution, but it looks to me like
what you're "missing" is how to sequence commands, which is the whole
purpose of the "do" notation.

print_list [] = return ()
print_list (x:xs) =
  do putStr x
       print_list xs

The do notation is used here to sequence to IO actions (which answers
your second question), first it prints out the first character in the
string, then it calls itself recursively to print the rest of the
list.
The empty list shouldn't print an empty string, it should do nothing
(that is, just return IO () because that's the return type of
print_list)

/S
--
Sebastian Sylvan
+46(0)736-818655
UIN: 44640862
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to print a string (lazily)

Daniel Carrera-2
Sebastian Sylvan wrote:

> Others have already replied with a solution, but it looks to me like
> what you're "missing" is how to sequence commands, which is the whole
> purpose of the "do" notation.
>
> print_list [] = return ()
> print_list (x:xs) =
>   do putStr x
>        print_list xs
>
> The do notation is used here to sequence to IO actions (which answers
> your second question), first it prints out the first character in the
> string, then it calls itself recursively to print the rest of the
> list.

Thanks! And yes, I'm just learning how to sequence commands/actions, so
I know I'm missing a lot.

> The empty list shouldn't print an empty string, it should do nothing
> (that is, just return IO () because that's the return type of
> print_list)

Yeah... I just didn't know how to "do nothing" with Haskell. Thanks!

Cheers,
Daniel.
--
      /\/`) http://oooauthors.org
     /\/_/  http://opendocumentfellowship.org
    /\/_/
    \/_/    I am not over-weight, I am under-tall.
    /
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to print a string (lazily)

Daniel Carrera-2
In reply to this post by haskell-2
Chris Kuklewicz wrote:
> What does lazy printing mean?
>
> I assume it means you evaluate the head of the list, print it, then
> recursively do this for the tail of the list.  With an infinite list you
> will get inifinite output.
>
> I assume it does not mean you evaluate the whole list before printing
> anything.  This would prevent infinite lists from producing output.

Yes, that's exactly what I had in mind. I wanted to print [1..] (an
infinite list) with each number on a different line.

Thanks for the help. Yes, the function works now.

> main = do
>   let hw = ["Hello"," ","World","!"]
>   mapM_ putStr hw
>   mapM_ putStrLn hw
>   putStr (unlines hw) -- see also: unwords, words, lines
>   printList hw

Cool. I didn't know about (un)words and unlines.

Cheers,
Daniel.
--
      /\/`) http://oooauthors.org
     /\/_/  http://opendocumentfellowship.org
    /\/_/
    \/_/    I am not over-weight, I am under-tall.
    /
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to print a string (lazily)

Donn Cave-2
In reply to this post by haskell-2
On Tue, 3 Jan 2006, Chris Kuklewicz wrote:
...
> I sometimes call a function with side-effects in IO a "command".  But
> the terms are fungible.  But calling putStr a "function" is correct.  It
> is not a "pure function" however.

Is that the standard party line?  I mean, we all know its type and
semantics, whatever you want to call them, but if we want to put names
to things, I had the impression that the IO monad is designed to work
in a pure functional language - so that the functions are indeed actually
pure, including putStr.  It's the monad that actually incurs the side
effects.  Or something like that.  So it isn't at all necessary to have
another word for functions of type IO a.

        Donn Cave, [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: How to print a string (lazily)

Daniel Carrera-2
In reply to this post by Neil Mitchell
Neil Mitchell wrote:
> All Haskell functions are lazy, hence there is no need to "write a
> lazy version" of your print_list function. I think the function you
> probably want is:
>
> putStr (unlines xs)

Hhmm... that does work, and I'm a bit surprised that it does. I guess
I'm still stuck in the eager computation mindset. I would expect putStr
to have to wait for the (unlines xs) to be finished before doing any
printing, but it doesn't.

Some day I'll get the hang of this lazy evaluation thing. :)

> The first one has fewer monads, so I prefer it, but take your pick :)

Monads scare me, so I'll pick the first :)  Thanks!

Cheers,
Daniel.
--
      /\/`) http://oooauthors.org
     /\/_/  http://opendocumentfellowship.org
    /\/_/
    \/_/    I am not over-weight, I am under-tall.
    /
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to print a string (lazily)

Adrian Hey
In reply to this post by Donn Cave-2
On Tuesday 03 Jan 2006 6:11 pm, Donn Cave wrote:
> On Tue, 3 Jan 2006, Chris Kuklewicz wrote:
> ...
>
> > I sometimes call a function with side-effects in IO a "command".  But
> > the terms are fungible.  But calling putStr a "function" is correct.  It
> > is not a "pure function" however.
>
> Is that the standard party line?

I don't think so. putStr certainly is a pure function.
Try running..
main :: IO ()
main = let action = putStr "Bye"
       in action `seq` action
..and see what happens.

Regards
--
Adrian Hey




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

Re: How to print a string (lazily)

Sebastian Sylvan
In reply to this post by Daniel Carrera-2
On 1/3/06, Daniel Carrera <[hidden email]> wrote:

> Neil Mitchell wrote:
> > All Haskell functions are lazy, hence there is no need to "write a
> > lazy version" of your print_list function. I think the function you
> > probably want is:
> >
> > putStr (unlines xs)
>
> Hhmm... that does work, and I'm a bit surprised that it does. I guess
> I'm still stuck in the eager computation mindset. I would expect putStr
> to have to wait for the (unlines xs) to be finished before doing any
> printing, but it doesn't.
>
> Some day I'll get the hang of this lazy evaluation thing. :)

It does, in a sense, but since unlines is lazy (just like *everything
else* in Haskell) it won't actually *do* anything until putStr demands
an element from the result.

/S

--
Sebastian Sylvan
+46(0)736-818655
UIN: 44640862
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to print a string (lazily)

Ezra Cooper
On Jan 3, 2006, at 6:30 PM, Sebastian Sylvan wrote:

> On 1/3/06, Daniel Carrera <[hidden email]> wrote:
>> Neil Mitchell wrote:
>>> All Haskell functions are lazy, hence there is no need to "write a
>>> lazy version" of your print_list function. I think the function you
>>> probably want is:
>>>
>>> putStr (unlines xs)
>>
>> Hhmm... that does work, and I'm a bit surprised that it does. I guess
>> I'm still stuck in the eager computation mindset. I would expect
>> putStr
>> to have to wait for the (unlines xs) to be finished before doing any
>> printing, but it doesn't.
>>
>> Some day I'll get the hang of this lazy evaluation thing. :)
>
> It does, in a sense, but since unlines is lazy (just like *everything
> else* in Haskell) it won't actually *do* anything until putStr demands
> an element from the result.

... and, significantly, putStr will demand those elements one at a
time; each element of the list is, in turn, evaluated lazily, producing
(a) a next element and (b) a thunk representing the rest of the list.

In your example 'join' function,

   join [] = ""
   join (x:xs) = (show x) ++ "\n" ++ join xs

the caller will demand the first element of the list, which will force
the evaluation of (show x) but it will not immediately force the
evaluation of (join xs). That part stays as it is, living life as a
thunk, until the caller has demanded all the preceding elements and
still wants more.

hth,
Ezra

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

Re: How to print a string (lazily)

Cale Gibbard
In reply to this post by Donn Cave-2
On 03/01/06, Donn Cave <[hidden email]> wrote:

> On Tue, 3 Jan 2006, Chris Kuklewicz wrote:
> ...
> > I sometimes call a function with side-effects in IO a "command".  But
> > the terms are fungible.  But calling putStr a "function" is correct.  It
> > is not a "pure function" however.
>
> Is that the standard party line?  I mean, we all know its type and
> semantics, whatever you want to call them, but if we want to put names
> to things, I had the impression that the IO monad is designed to work
> in a pure functional language - so that the functions are indeed actually
> pure, including putStr.  It's the monad that actually incurs the side
> effects.  Or something like that.  So it isn't at all necessary to have
> another word for functions of type IO a.
>
I'd say it depends on the way that you're thinking about it. Strictly
speaking, putStr is a pure function which returns an action. It's also
referentially transparent, since it always returns the same action for
the same string.

However, if you think of functions a -> IO b as the arrows a -> b in a
new category where composition is Kleisli composition:

(@@) :: Monad m => (a -> m b) -> (t -> m a) -> (t -> m b)
y @@ x = \u -> x u >>= y

Then these arrows are "effectful" and would be considered impure.

I think I prefer the first explanation, as it's a somewhat important
property that the same action is computed for the same input. This
doesn't hold of side-effectful arrows in general. Note that with
Hughes' Arrows, this restriction can (often quite cleverly) be
side-stepped in order to make some rather major optimisations.

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

Re: How to print a string (lazily)

Tomasz Zielonka
In reply to this post by Neil Mitchell
On Tue, Jan 03, 2006 at 05:49:07PM +0000, Neil Mitchell wrote:

> All Haskell functions are lazy, hence there is no need to "write a
> lazy version" of your print_list function. I think the function you
> probably want is:
>
> putStr (unlines xs)
>
> This uses the bulid in unlines function, which is similar in spirit to
> join (you get more quotes, which I guess you don't want)
>
> The equivalent in monad'y programming is:
>
> mapM putStrLn xs
>
> The first one has fewer monads, so I prefer it, but take your pick :)

Nitpicking a bit to prevent possible confusion: a monad is a *type
constructor*, not an expression. In both variants above you are dealing
with two monads - IO and [] - however, the Monad instance for [] is
not used.

Best regards
Tomasz

--
I am searching for programmers who are good at least in
(Haskell || ML) && (Linux || FreeBSD || math)
for work in Warsaw, Poland
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to print a string (lazily)

Udo Stenzel
In reply to this post by Daniel Carrera-2
Daniel Carrera wrote:
> I've been studying more Haskell and I've improved a lot. But I just hit
> a small problem. I want to print all the elements of a linst (putStr).
> I'd like to write something like this:
>
> print_list [] = do putStr ""

This looks as if you're confused.  The keyword "do" is completely
redundant.  "do" does not mean "please ignore all rules and allow side
effects", it rather means "please build a new action by sequencing what
follows".  So "do" with only one action after it is useless (and a sign
of confusion).  Have you ever heard about the "command" and "composite"
design patterns?  Well, in Haskell, you get them for free with monads.


> print_list (x:xs) = (do putStr x) && print_list xs

print_list (x:xs) = do putStr x ; print_list xs


 
> print_list xs = do putStr(join xs)
> where join [] = ""
>      join (x:xs) = (show x) ++ "\n" ++ join xs
>
> But the thing is, I want to write a lazy version of this function.

What's not lazy about it?  If you think, join has to "complete" "before"
putStr can be called, simply forget it.  Those words don't even make
sense in a lazy functional setting.


Udo.
--
Lost: gray and white female cat.  Answers to electric can opener.

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

signature.asc (196 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: How to print a string (lazily)

Wolfgang Jeltsch
In reply to this post by Daniel Carrera-2
Am Dienstag, 3. Januar 2006 19:15 schrieb Daniel Carrera:

> Neil Mitchell wrote:
> > All Haskell functions are lazy, hence there is no need to "write a
> > lazy version" of your print_list function. I think the function you
> > probably want is:
> >
> > putStr (unlines xs)
>
> Hhmm... that does work, and I'm a bit surprised that it does. I guess
> I'm still stuck in the eager computation mindset. I would expect putStr
> to have to wait for the (unlines xs) to be finished before doing any
> printing, but it doesn't.

(unlines xs) is only evaluated on demand.  Think of putStr as defined as
follows:

        putStr :: String -> IO ()
        putStr []
                = return ()
        putStr (x : xs)
                = do
                        putChar x
                        putStr xs

Every character of the string is evaluated when it is needed by putChar x, not
earlier.  So the argument of putStr is evaluated lazily.

> [...]

> Some day I'll get the hang of this lazy evaluation thing. :)

Yes. :-)  Lazy evaluation is really powerful. ;-)

> > The first one has fewer monads, so I prefer it, but take your pick :)
>
> Monads scare me, so I'll pick the first :)  Thanks!

It is preferable because it does more of the work without imperative
programming.

> Cheers,
> Daniel.

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

Re: How to print a string (lazily)

Tomasz Zielonka
In reply to this post by Udo Stenzel
On Tue, Jan 03, 2006 at 10:28:54PM +0100, Udo Stenzel wrote:
> Daniel Carrera wrote:
> > print_list [] = do putStr ""
>
> This looks as if you're confused.  The keyword "do" is completely
> redundant.  "do" does not mean "please ignore all rules and allow side
> effects", it rather means "please build a new action by sequencing what
> follows".  So "do" with only one action after it is useless (and a sign
> of confusion).

Perhaps you are right, but this can also be a sign of version-control
awareness, and I know Daniel uses darcs.

I often place a single command in a do-block, because I want future
changes to touch as little lines as possible. Consider:

    f = putStrLn "b"

and
   
    f = do
        putStrLn "b"

If you'll later add more commands, you'll get something like:

    f = do
        x <- g
        putStrLn "b"
        putStrLn x

which is much closer to the reduntant-do variant.

Best regards
Tomasz

--
I am searching for programmers who are good at least in
(Haskell || ML) && (Linux || FreeBSD || math)
for work in Warsaw, Poland
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to print a string (lazily)

Glynn Clements
In reply to this post by Donn Cave-2

Donn Cave wrote:

> > I sometimes call a function with side-effects in IO a "command".  But
> > the terms are fungible.  But calling putStr a "function" is correct.  It
> > is not a "pure function" however.
>
> Is that the standard party line?  I mean, we all know its type and
> semantics, whatever you want to call them, but if we want to put names
> to things, I had the impression that the IO monad is designed to work
> in a pure functional language - so that the functions are indeed actually
> pure, including putStr.

putStr is a pure function, but it isn't a "pure function" ;)

OTOH, getLine isn't even a function, just a value.

--
Glynn Clements <[hidden email]>
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe