
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.

Daniel Carrera wrote:
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.
Oooohh baby, you sure have stumbled across the proverbial can'o'worms. Yes, others have asked themselves "the" question, and some have dedicated a large slab of their waking hours trying to make some sense of it all. Many aspects of functional programming are generalisations of what goes on in imperative languages. One might expect this would make FP somewhat _more_ applicable, which is true - but there are complications. You might like to take a deep breath and start with: "Tackling the awkward squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell" - Simon Peyton Jones http://research.microsoft.com/Users/simonpj/papers/marktoberdorf/ It might give you a better overview of "the" problem. As for the solution.. uh... stay tuned. PS: Keep asking those questions.

Ben Lippmeier wrote:
You might like to take a deep breath and start with: "Tackling the awkward squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell" - Simon Peyton Jones
http://research.microsoft.com/Users/simonpj/papers/marktoberdorf/
Ok. And I'll get to learn what monadic IO is... :-)
PS: Keep asking those questions.
:-) I'm eager to learn. Cheers, Daniel.

Many aspects of functional programming are generalisations of what goes on in imperative languages.
Huh? In which sense is that?
All senses? examples: * I would say that let-polymorphic HM style type inference (with type classes) is a generalisation of C/C++/Java style type checking + operator overloading + templates. * The full laziniess transform is a generalisation of the "lifting things out of loops" optimisation which many imperative compilers do. * Its funny how imperative programmers get all excited about iterators and rejoice when foreach is added to their favourite language, when FPers have been mapping and folding for decades. I would say that once you've got higher order, polymorphic, first class functions, and a type system to keep the peace, well ... anything else you add is just icing on the cake :).

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
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@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Tue, May 03, 2005 at 12:38:25AM -0400, Daniel Carrera wrote:
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?
In my experience, the amount of IO code in an average Haskell program is from 1% to 20%, even in applications which have to do a fair amount of interaction with the outside world (networking, CGI, system utils). It may be more in GUI applications - I don't have much experience in this area. But I expect that the most interesting GUI applications aren't made for the sake of GUI, but to solve some algorithmically complicated problems, and solutions to such problems are often most easily implemented purely. I can't strictly define what "IO code" means for me, because IO and purely functional code are often so mixed in Haskell programs. This is also a great strength of Haskell - pure functions are very convenient as a glue for imperative actions. Haskell's IO is not just a mimicry of traditional imperative languages, it's an EDSL (embedded domain specific language) for doing IO. Because it's embedded it benefits from all the other features of Haskell, like first-class functions, higher-order functions, lexical closures, pattern matching, etc, etc. In fact, IO actions of a Haskell program are first computed, purely. You can build imperative programs on-the-fly, pass them to and from functions, store them in data structures, etc, etc. You can build your own abstractions, for example looping constructs. One nice difference between Haskell's IO actions and statements of imperative languages like C is that every IO action can yield a value. For example, a block of C code enclosed in braces cannot return a value. You might wan't to put code in such block to reduce the scope of some helper variables. In C if you want to "return" a value from such block you have to use assignment (in a way that detaches variable's declaration from its assignment) or move this code to a function. In Haskell you can: x <- do { ... ; ... ; return (some expression) } ...
So, I'm tempted to conclude that FP is only applicable to situations where user interaction is a small part of the program.
If you mean that Haskell is rarely applicable, I disagree. Best regards Tomasz

Tomasz Zielonka wrote:
In my experience, the amount of IO code in an average Haskell program is from 1% to 20%, even in applications which have to do a fair amount of interaction with the outside world (networking, CGI, system utils).
Ok, I can see that. Thanks.
Haskell's IO is not just a mimicry of traditional imperative languages, it's an EDSL (embedded domain specific language) for doing IO. Because it's embedded it benefits from all the other features of Haskell, like first-class functions, higher-order functions, lexical closures, pattern matching, etc, etc.
I guess this will make more sense to me as I learn more about the language. I'm quite new at this.
If you mean that Haskell is rarely applicable, I disagree.
Well... the purpose of asking here is so knowledgeable people can correct my errors. :-) Thank you for the info. I'm learning. Cheers, Daniel.

Hi all,
Again, I'm the new guy slowly learning this "fuctional programming" thing. :-)
[snip]
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.
You might want to check this out: http://www.md.chalmers.se/~rjmh/Papers/whyfp.html

On 5/3/05, Daniel Carrera
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.
Others have already touched most of it so I'll just summarized why I prefer Haskell even in cases where there's tons of IO. First of all, there's LESS stateful code. Code with state really is quite unintuitive (how often do you change the meaning of a name in real life?) so if most of your code is _guaranteed_ to be pure and free from state, then that's certainly better than having all of your code potentially tainted. Also in Haskell the IO computations are first class (unlike most imperative languages). So you can send computations to a function as a parameter, and write your own control structures (like for-loops for example) and it's just a lot easier to deal with in Haskell then it is in imperative languages since IO-computations are just haskell values and nothing "special". And finally, the impure code is separated clearly from the pure code. So you get an "imperative skin" which does interactions with the impure world outside, and a pure "functional core" which does the bulk of the real computations. /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

Daniel Carrera writes:
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.
I can't confirm that. I've written several I/O-intensive applications in Haskell, including full-blown network servers which arguably do nothing _but_ user interaction, and I haven't run into any problems I couldn't solve. Plus, most of the problems I've ran into were caused by non-strict evaluation rather than the purely functional design per se. The old saw of "right tool for the right job" certainly applies to Haskell too, but given the fact that there are _operating systems_ written in Haskell, I'd say that Haskell's scope is a lot broader than most people would think. Peter

On Tue, 2005-05-03 at 00:38 -0400, Daniel Carrera wrote:
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.
Others have suggested this is not always true. If you dig around you will find some computer games written in purely functional languages. I think these qualify as programs where user interaction is not a small part of the program. A very nice demonstration for the Clean programming language can be found at this link: http://www.cs.ru.nl/~clean/About_Clean/Platform_Games/platform_games.htm I believe that the low-level game environment is written in C. However, to make a new game you only need to write Clean code, the game environment is just linked in at the end. The conclusion might be in this case that C is better for the low-level bit twiddling needed for every game, but Clean is better for constructing the logic of new games. My personal experience tends to agree with this conclusion. Clean is not Haskell, but they are very closely related. Cheers, Bernie.
participants (9)
-
Ben Lippmeier
-
Bernard Pope
-
Daniel Carrera
-
Jeremy Shaw
-
Michael Walter
-
Peter Simons
-
robert dockins
-
Sebastian Sylvan
-
Tomasz Zielonka