[Haskell-cafe] Where do you use Haskell?

Jeremy Shaw Jeremy.Shaw at linspireinc.com
Tue May 3 04:04:37 EDT 2005


Hello,

What if main had a function prototype like:

main :: String -> String

And you passed stdin to main as string, and you print the output of main
to stdout.

As long as you run the program with the same stdin, when main calls
'ask_user_name stdin', you will always get the same answer, right ?
And, you have not violated referencial transparency -- for the same
input,
you get the same output, and there are no side-effects.

Back in the day, this is approximately how IO was done in haskell. See
the function 'interact' for more information about that method.

That method obviously has limitations, such as only being able to read
from
stdin and write to stdout -- most real programs want to read from lots 
of files, or talk to a network, interact with a mouse cursor, etc.

But the basic idea can be extended -- imagine if main had a function
prototype
more like,

main :: RealWorld -> RealWorld

Where RealWorld is not just stdin, but everything that your program is
going
to interact with -- files on the disk, network sockets, etc. Then you
could
do things like,

main rw =
  let (username, rw') = get_user_name rw in
    let rw'' = putStrLn rw' username in
      rw''

As long as you pass in the same rw everytime, you should get the same
results. Of course, everytime something like get_user_name or putStrLn
interacts with the rw, it changes it (for example, the file pointer
moves).
Since we can't have 'side-effects', putStrLn or get_user_name must
return
a new version of rw that reflects the changes they have made. So, we are
still maintaining referecial transparency (for the same input you get
the
same output), and there are no 'side-effects' -- all the effects of the
function are explicitly returned as a modified version of rw.

Of course, writing the above code is really tricky in practice, because
you can only use each version of rw once -- otherwise you would be using
an old state of the world that is no longer accurate. It is very
easy to accidently use the same version of rw more than once.

In concurrent clean, they solve this problem by having the compiler
do uniqueness type checking. The compiler knows that each version of
rw can only be used once and it will generate a compile time error if
you
accidently use it twice.

In haskell, we solve the problem by using monads to ensure that each
copy of rw is only used once. As a matter of fact, monads free the
user from having to deal directly with rw at all -- which is very nice.

The important thing to realize is that monads (aka, do ... <- work),
are not some hack where we suddenly allow side-effects. Monads are
useful for many things -- one of which is making sure state variables
are used in a sane manner. The IO monad is designed specifically
handling the RealWorld state so you can do useful IO. 

If you read the paper reference in another message (Tackling the 
awkward squad), I believe he covers this in more detail (and more
clarity).

In any case, as long as the same RealWorld is passed into the program
everytime, you get the same output everytime. The trick is getting
RealWorld to be exactly the same each time. Conceptually, RealWorld
needs to contain the entire state of the world that could affect your
program. So, if you hard drive is destined to crash half way through
the program -- that needs to be encoded into RealWorld. Pragmatically,
RealWorld can only encode a limited amount of information, like file
handles, etc. Because RealWorld is missing some information, you can
get different results from one run to the next, even if RealWorld 
is identical. For example, if you type in a different name to
ask_user_name, then you will get a different result, even if the inital
RealWorld was the same. Techinally, the name that you are going to type
in, should be stored in RealWorld when the program starts, but no one
has figured out how to see that far into the future yet...

I hope this makes some sense (and I hope what I have said is reasonably
correct...)

Jeremy Shaw.

On May 02, 2005 09:38 PM, Daniel Carrera
<dcarrera at digitaldistribution.com> wrote:

> Hi all,
> 
> Again, I'm the new guy slowly learning this "fuctional programming" 
> thing. :-)
> 
> I've been reading, and I'm really liking the elgance of Haskell, and
> FP
> as a whole. But I wonder about the range of applicability. You see,
> one
> of the things about FP is that there are no side-effects and the same 
> function on the same parameters always returns the same value. But any
> program that interacts with the real world cannot meet those
> properties.
> 
> The function ask_user_name() will not return the same value each time.
> If write a chess program, the function get_user_move() will be
> different
> each time. And every time you update the screen, you're having a 
> side-effect.
> 
> So, I figure that to do these tasks you heed that "do ... <-" work 
> around. But that kills the whole point of using FP in the first place,
> right?
> 
> So, I'm tempted to conclude that FP is only applicable to situations 
> where user interaction is a small part of the program. For example,
> for
> simulations.
> 
> Now, I'm sure I'm not the first person to have this train of thought. 
> And I'm sure there is a good answer why I'm wrong. :-) I'm eager to
> hear
> what that might be.
> 
> Cheers,
> Daniel.
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe



More information about the Haskell-Cafe mailing list