Theoretical question: are side effects necessary?

Dear all, there is a question I have been thinking about a bit. In short, we could simply formulate it like this: Are there any problems which *cannot *be solved a side effect-free language (such as Haskell)? In other words, are there problems that would explicitly demand semantics that can only be provided by a language allowing direct modification of external state variables, such as Java and C++? If not, are there problems which are simply *infeasible *to solve with a side effect-free language? I realize this question is very broad, and I am not expecting an exact answer by any means. I am asking since I am curious about the relation between functional and imperative/procedural languages in general. I primarily come from a Java background, but I can program Haskell and Erlang, and have recently started exploring Scala, so this would be interesting to know. -- Best, Christopher Svanefalk Student, Department of Computer Science and Engineering University of Gothenburg / Chalmers University of Technology

Christopher, On 16/03/2012, at 11:23 PM, Christopher Svanefalk wrote:
there is a question I have been thinking about a bit. In short, we could simply formulate it like this:
Are there any problems which cannot be solved a side effect-free language (such as Haskell)? In other words, are there problems that would explicitly demand semantics that can only be provided by a language allowing direct modification of external state variables, such as Java and C++?
If not, are there problems which are simply infeasible to solve with a side effect-free language?
Start here: http://www.cs.ox.ac.uk/people/geraint.jones/morehaste.html and dig through their references. I don't think "a logarithmic factor" is ever going to make the difference between feasible and infeasible. :-) cheers peter -- http://peteg.org/

On Fri, Mar 16, 2012 at 9:23 AM, Christopher Svanefalk
Are there any problems which cannot be solved a side effect-free language (such as Haskell)? In other words, are there problems that would explicitly demand semantics that can only be provided by a language allowing direct modification of external state variables, such as Java and C++?
Haskell, Java, C++ and most other languages out there are Turing-complete. That means that all of them are able to compute the same things. Assuming that the Church-Turing hypothesis is true, all algorithms may be coded in all of them.
If not, are there problems which are simply infeasible to solve with a side effect-free language?
If you're asking about performance, as in "is there a problem that can be solved in O(f(n)) time in Java but not in Haskell-sans-IO-and-ST?", then it becomes a harder question. I'm not sure what the answer is. Cheers, -- Felipe.

On Fri, Mar 16, 2012 at 8:35 AM, Felipe Almeida Lessa < felipe.lessa@gmail.com> wrote:
If you're asking about performance, as in "is there a problem that can be solved in O(f(n)) time in Java but not in Haskell-sans-IO-and-ST?", then it becomes a harder question. I'm not sure what the answer is.
Cheers,
-- Felipe.
</lurk> an interesting question emerges: even though i may be able to implement an algorithm with O(f(n)) in Haskell, and write a program that is O(g(n)) < O(f(n)) in C++ or Java... could Haskell be said to be more efficient if time spent programming / maintaining Haskell is << C++ or Java?? i'm still trying to learn Haskell, but it seems to me to be *much* less verbose than C and it's derivatives, and while jumping through monads just to print to a screen or write a file seems a small expence to pay to be able to express what you want easier... justin <lurk> -- * The wise man said: "Never argue with an idiot. They bring you down to their level and beat you with experience." * As a programmer, it is your job to put yourself out of business. What you do today can be automated tomorrow. ~Doug McIlroy No snowflake in an avalanche ever feels responsible. --- CFO: “What happens if we train people and they leave?” CTO: “What if we don’t and they stay?”

On Fri, Mar 16, 2012 at 3:43 PM, serialhex
an interesting question emerges: even though i may be able to implement an algorithm with O(f(n)) in Haskell, and write a program that is O(g(n)) < O(f(n)) in C++ or Java... could Haskell be said to be more efficient if time spent programming / maintaining Haskell is << C++ or Java??
There are two unrelated issues: (a) the efficiency of algorithms implementable in Haskell, and (b) the efficiency of programmers working in Haskell. It makes no sense to ask a question that conflates the two. If you're unsure which definition of "efficient" you meant to ask about, then first you should stop to define the words you're using, and then ask a well-defined question. That being said, this question is even more moot given that real Haskell, which involves the IO and ST monads, is certainly no different from any other language in its optimal asymptotics. Even if you discount IO and ST, lazy evaluation alone *may* recover optimal asymptotics in all cases... it's known that a pure *eager* language can add a log factor to the best case sometimes, but my understanding is that for all known examples where that happens, lazy evaluation (which can be seen as a controlled benign mutation) is enough to recover the optimal asymptotics. -- Chris Smith

If the question is "when can I have my output", then both are equally
relevant and can be safely conflated.
That said, while some programming problems *are* of this type, I think
most aren't, and your points certainly stand.
On Fri, Mar 16, 2012 at 3:31 PM, Chris Smith
On Fri, Mar 16, 2012 at 3:43 PM, serialhex
wrote: an interesting question emerges: even though i may be able to implement an algorithm with O(f(n)) in Haskell, and write a program that is O(g(n)) < O(f(n)) in C++ or Java... could Haskell be said to be more efficient if time spent programming / maintaining Haskell is << C++ or Java??
There are two unrelated issues: (a) the efficiency of algorithms implementable in Haskell, and (b) the efficiency of programmers working in Haskell. It makes no sense to ask a question that conflates the two. If you're unsure which definition of "efficient" you meant to ask about, then first you should stop to define the words you're using, and then ask a well-defined question.
That being said, this question is even more moot given that real Haskell, which involves the IO and ST monads, is certainly no different from any other language in its optimal asymptotics. Even if you discount IO and ST, lazy evaluation alone *may* recover optimal asymptotics in all cases... it's known that a pure *eager* language can add a log factor to the best case sometimes, but my understanding is that for all known examples where that happens, lazy evaluation (which can be seen as a controlled benign mutation) is enough to recover the optimal asymptotics.
-- Chris Smith
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Hi there,
Christopher Svanefalk
there is a question I have been thinking about a bit. In short, we could simply formulate it like this:
Are there any problems which *cannot *be solved a side effect-free language (such as Haskell)? In other words, are there problems that would explicitly demand semantics that can only be provided by a language allowing direct modification of external state variables, such as Java and C++?
If not, are there problems which are simply *infeasible *to solve with a side effect-free language?
I realize this question is very broad, and I am not expecting an exact answer by any means. I am asking since I am curious about the relation between functional and imperative/procedural languages in general. I primarily come from a Java background, but I can program Haskell and Erlang, and have recently started exploring Scala, so this would be interesting to know.
Every problem is solvable in a pure language like Haskell, but I guess you are more interested in the fundamentals. There is a proof that lambda calculus (which is the smallest common denominator of all purely functional languages) is equivalent to the model of Turing machines. That basically means that any computer program can be written in both. Adding types changes the whole picture. In the typed lambda calculus not every program can be expressed. Particularly every program in this model must terminate. To get back the full expressivity you need to add an (opaque) general recursion operator, and most languages do that by allowing a definition to refer to any other, including itself. Many of them (F#, OCaml) have an explicit "let rec"-style construct, others (Haskell, Clean) allow recursion everywhere. Functional languages with a more powerful type system (like Agda) even refrain from adding general recursion. These are in fact not Turing-complete. Without general recursion you can use a language for proofs, whether you prove theorems or program behavior. Still you can express infinite recursion using coinduction. About feasibility: For both models there is a set of problems which are hard to express, and they are fairly disjoint. Usually a hard to express problem in one is easy to express in the other. To add more expressivity imperative languages add language constructs (loops, OO, exceptions, etc.), while functional languages add combinators and composition patterns (monads, higher order functions, etc.). I think if a problem is infeasible to express in one model, it will be infeasible in the other as well. Greets, Ertugrul -- nightmare = unsafePerformIO (getWrongWife >>= sex) http://ertes.de/

Hi, Christopher Svanefalk wrote:
Are there any problems which *cannot* be solved a side effect-free language (such as Haskell)?
No. Haskell is expressive enough. One way to prove that is to implement an interpreter for a language with side effects in Haskell. Now if there's a program P to solve a problem in the language-with-side-effects, we can run that interpreter on P to solve the same problem in Haskell. The interpreter could use a Data.Map to associate variable names with values. That would probably not be the fastest or the most memory efficient implementation of the language-with-side-effects, but it would work. The same trick of implementing one language in the other can be done for almost every pair of "reasonably expressive languages", so they are all equally expressive in a sense. It is even widely believed that no even more expressive language can exist. That means that if a problem can be solved by a computer at all, it can also be solved using any of these "reasonably expressive languages". That is the Church-Turing-Hypothesis. (And the other way around: if the hypothesis is true, and a problem can not be solved in one of these languages, that problem cannot be solved with a computer at all. Unfortunately, many interesting problems are like that). Tillmann

You can emulate mutation with at most O(log(n)) penalty using a map. Given that memory is of fixed size, log2(n) <= 64, so for "real-world" programs this becomes O(1). So any program you can implement using mutation can be implemented in a pure language with the same big-O running time (but much much worse constant factors, given this naive translation). Other external state is harder to emulate. For example, communication over a network most definitely requires some concept of a 'computation with side effects' since the network's response could change from request to request. In GHC, even IO objects are pure, but they conceptually represent functions that modify the state of reality. -- ryan On Fri, Mar 16, 2012 at 5:23 AM, Christopher Svanefalk < christopher.svanefalk@gmail.com> wrote:
Dear all,
there is a question I have been thinking about a bit. In short, we could simply formulate it like this:
Are there any problems which *cannot *be solved a side effect-free language (such as Haskell)? In other words, are there problems that would explicitly demand semantics that can only be provided by a language allowing direct modification of external state variables, such as Java and C++?
If not, are there problems which are simply *infeasible *to solve with a side effect-free language?
I realize this question is very broad, and I am not expecting an exact answer by any means. I am asking since I am curious about the relation between functional and imperative/procedural languages in general. I primarily come from a Java background, but I can program Haskell and Erlang, and have recently started exploring Scala, so this would be interesting to know.
-- Best,
Christopher Svanefalk
Student, Department of Computer Science and Engineering University of Gothenburg / Chalmers University of Technology
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Ryan Ingram:
Other external state is harder to emulate. For example, communication over a network most definitely requires some concept of a 'computation with side effects' since the network's response could change from request to request.
In GHC, even IO objects are pure, but they conceptually represent functions that modify the state of reality. I believe I begin to become a sectarian, with some idées fixes not so well shared...
It is the third or the fourth time that somebody recently puts the equivalence between the communication with the outer world, and "side effects". I contest that very strongly, perhaps a TRUE guru might instruct me. What a computer and the program it runs do to its hard environment has NOTHING to do with side-effects. Even a completely angelic, pure as a Cherub (but real) program will consume some electricity. And so what?! Of course, in classical physics the state of the world changes constantly (in a quantum world it is extremely ambiguous...), but the question of purity of a program - in my opinion - concerns the program, and nothing else. The networking is not expected to break the referential transparency, or does it? Jerzy Karczmarczuk

It is the third or the fourth time that somebody recently puts the equivalence between the communication with the outer world, and "side effects". I contest that very strongly, perhaps a TRUE guru might instruct me.
I think there are three key concepts rumbling around in this discussion that are related, but distinct: determinism, purity, and side effects. An easy trap to fall into is the idea that determinism = purity, when really they are not the same. There is a set of functions that are deterministic, but not pure. An example is putMVar: *putMVar* http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Con...:: MVar a -> a -> IO () http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Con... On the other hand, there are functions that are non-deterministic, but pure: nondeterministicAndPure :: () -> MonadState Int Int nondeterministicAndPure () = do x <- get return x Then, there are functions that are both deterministic and pure, like lookup, and functions that are neither deterministic, nor pure, like takeMVar. I'm thinking that side effects are really only necessary because Haskell programs expect to mutate the state of a computer outside of the haskell program. Perhaps if we had Haskell OS, everything could live in some giant MonadState, and IO could be disposed of entirely. Jeff

Quoth Jeff Shaw
I'm thinking that side effects are really only necessary because Haskell programs expect to mutate the state of a computer outside of the haskell program.
I'm not a computer scientist, but in English, "side effect" is an effect that accompanies some other effect. E.g., you may take an antihistamine to relieve hay fever, and experience a side effect of drowsiness. Let's call the first an `intended effect'? Then in the matter of the computer outside the Haskell program - which is intended effect, and which is side effect? I'd have said, side effects would be like memory paging, deferred resource access for other processes, etc.? Some programs might leave behind temporary files ... I hope the answer is not that in computer science we regard all effects as side effects because the ideal computer program simply exists without consequence. Donn

On Sat, Mar 17, 2012 at 5:41 AM, Donn Cave
I hope the answer is not that in computer science we regard all effects as side effects because the ideal computer program simply exists without consequence.
The answer is that side effects has become something of a figure of speech, and now has a specialized meaning in programming languages. When we're talking about different uses of the word "function" in programming languages, side effects refer to any effect other than evaluating to some result when applied to some argument. For example, in languages like C, printf takes some arguments, and returns an int. When viewed as just a function, that's all there is to it; functions exist to take arguments and produce return values. But C extends the definition of a function to include additional effects, like making "Hello world" appear on a nearby computer screen. Because those effects are "aside from" the taking of arguments and returning of values that functions exist to do, they are "side effects"... even though in the specific case of printf, the effect is the main goal and everyone ignores the return value, still for functions in general, any effects outside of producing a resulting value from its arguments are "side effects". I suppose Haskell doesn't have "side effects" in that sense, since its effectful actions aren't confused with functions. (Well, except from silly examples like "the CPU gives off heat" or FFI/unsafe stuff like unsafePerformIO.) So maybe we should ideally call them just "effects". But since so many other languages use functions to describe effectful actions, the term has stuck. So pretty much when someone talks about side effects, even in Haskell, they means stateful interaction with the world. -- Chris Smith

Quoth Chris Smith
The answer is that side effects has become something of a figure of speech, and now has a specialized meaning in programming languages.
When we're talking about different uses of the word "function" in programming languages, side effects refer to any effect other than evaluating to some result when applied to some argument. For example, in languages like C, printf takes some arguments, and returns an int. When viewed as just a function, that's all there is to it; functions exist to take arguments and produce return values.
I'm surprised by the use of "function" as a unit. I would have expected "expression" or something, but maybe that isn't semantically interesting as long as one can't exist independent of the other.
... But C extends the definition of a function to include additional effects, like making "Hello world" appear on a nearby computer screen. Because those effects are "aside from" the taking of arguments and returning of values that functions exist to do, they are "side effects"... even though in the specific case of printf, the effect is the main goal and everyone ignores the return value, still for functions in general, any effects outside of producing a resulting value from its arguments are "side effects".
If that's so, it's unfortunate. It would have been more profitable to confine the application of this term (side effect) to the context of the program, where it 1) makes sense in English, and 2) applies to a programming device that has always been of some interest. I have a little trouble defending this point of view because there's some overlap, inasmuch as the program may also retrieve values via external I/O. And Haskell provides writeIORef/readIORef as a convenient way to demonstrate that as a technical side effect without resorting to actual I/O. Still, the use of I/O and similar techniques to create a side effect are interesting as such, and my point is that if we call every I/O a side effect, the term loses its value as a way to describe this programming feature. Donn

Ryan Ingram
You can emulate mutation with at most O(log(n)) penalty using a map. Given that memory is of fixed size, log2(n) <= 64, so for "real-world" programs this becomes O(1).
I'm not sure assuming fixed size memory is a good idea for a theoretical discussion - your computer is no longer Turing complete, and one type of implementation will likely be able to fit a different set of programs in the given memory than the oher. Another nit: this is O(log(n)) of working set, not input/problem size. But I guess any algorithm must be at least O(working set size), so it's still a log factor (or less) of the algorithmic complexity. -k -- If I haven't seen further, it is by standing in the footprints of giants
participants (13)
-
Chris Smith
-
Christopher Svanefalk
-
David Thomas
-
Donn Cave
-
Ertugrul Söylemez
-
Felipe Almeida Lessa
-
Jeff Shaw
-
Jerzy Karczmarczuk
-
Ketil Malde
-
Peter Gammie
-
Ryan Ingram
-
serialhex
-
Tillmann Rendel