The question of imperative versus pure declarative coding has brought to my mind some may be off-topic speculations.  (so please donīt read it if you have no time to waste):  Iīm interested in the misterious relation bentween mathematics, algoritms and reality (see this for example).  Functional programming is declarative, you can model the entire world functionally with no concern for the order of calculations. The world is mathematical. The laws of physics have no concern for sequencing.

But CPUs and communications are basically sequential.  Life is sequential, and programs run along the time coordinate. Whenever you have to run a program,  you or your compiler must sequence it.  The sequentiation  must be done by you or your compiler or both. The functional declarative code can be sequenced on-the-run by the compiler in the CPU by the runtime. but IO is different. 

You have to create, explicitly or implicitly the sequence of IO actions because the external events in the external world  are not controlled by you or the compiler. So you, the programmer are the responsible of sequencing effects in coordination with the external world. so every language must give you ways to express  sequencing of actions. that is why, to interact with the external world you must think in terms of algorithms, that is , imperatively, no matter if you make the imperative-sequence  (relatively) explicit with monads or if you make it trough pairs (state, value) or unsafePerformIO or whatever. You have to think imperatively either way, because yo HAVE TO construct a sequence. I think that the elegant option is to recognize this different algorithmic nature of IO by using the IO monad.

In other terms, the appearance of input-output in a problem means that you modelize just a part of the whole system. the interaction with the part of the system that the program do not control appears as input output. if the program includes the model of the environment that give the input output (including perhaps a model of yourself), then, all the code may be side effects free and unobservable. Thus, input output is a measure of the lack of  a priori information.  Because this information is given and demanded at precide points in the time dimension with a quantitative (real time) or ordered (sequential) measure, then these impure considerations must be taken into account in the program. However, the above is nonsensical, because if you know everithing a priory, then you donīt have a problem, so you donīt need a program. Because problem solving is to cope with unknow data that appears AFTER the program has been created, in oder to produce output at the corrrect time, then the program must have timing on it. has an algoritmic nature, is not pure mathemathical. This applies indeed to all living beings, that respond to the environment, and this creates the notion of time.


Concerning monadic code with no side effects, In mathematical terms,  sequenced (monadic) code are mathematically different from declarative code: A  function describes what in mathematics is called a  "manifold" with a number of dimensions equal to the number of parameters.  In the other side, a sequence describe a particular  trayectory in a manifold, a ordered set of points in a wider manyfold surface. For this reason the latter must be described algorithmically. The former can be said that include all possible trajectories, and can be expressed declaratively. The latter is a sequence  . You can use the former to construct the later, but you must   express the sequence because you are defining the concrete trajectory in the general manifold that solve your concrete problem, not other infinite sets of related problems. This essentially applies also to IO.

 Well this does not imply that you must use monads for it. For example, a way to express a sequence is a list where each element is a function of the previous.  The complier is forced to sequence it in the way you whant, but this happens also with monad evaluation.  

This can be exemplified with the laws of Newton: they are declarative. Like any phisical formula. has no concern for sequencing. But when you need to simulate the behaviour of a ballistic weapon, you must use a sequence of instructions( that include the l newton laws). (well, in this case the trajectory is continuous integrable and can be expressed in a single function. In this case, the manifold includes a unique trajectory, but  this is not the case in ordinary discrete problems,) . So any language need declarative as well as imperative elements to program mathematical models as well as algorithms.


Cheers
  Alberto.

2009/1/11 Apfelmus, Heinrich <apfelmus@quantentunnel.de>
Ertugrul Soeylemez wrote:
> Let me tell you that usually 90% of my code is
> monadic and there is really nothing wrong with that.  I use especially
> State monads and StateT transformers very often, because they are
> convenient and are just a clean combinator frontend to what you would do
> manually without them:  passing state.

The insistence on avoiding monads by experienced Haskellers, in
particular on avoiding the IO monad, is motivated by the quest for elegance.

The IO and other monads make it easy to fall back to imperative
programming patterns to "get the job done". But do you really need to
pass state around? Or is there a more elegant solution, an abstraction
that makes everything fall into place automatically? Passing state is a
valid implementation tool, but it's not a design principle.


A good example is probably the HGL (Haskell Graphics Library), a small
vector graphics library which once shipped with Hugs. The core is the type

 Graphic

which represents a drawing and whose semantics are roughly

 Graphic = Pixel -> Color

There are primitive graphics like

 empty   :: Graphic
 polygon :: [Point] -> Graphic

and you can combine graphics by laying them on top of each other

 over    :: Graphic -> Graphic -> Graphic

This is an elegant and pure interface for describing graphics.

After having constructed a graphic, you'll also want to draw it on
screen, which can be done with the function

 drawInWindow :: Graphic -> Window -> IO ()

This function is in the IO monad because it has the side-effect of
changing the current window contents. But just because drawing on a
screen involves IO does not mean that using it for describing graphics
is a good idea. However, using IO for *implementing* the graphics type
is fine

 type Graphics = Window -> IO ()

 empty          = \w -> return ()
 polygon (p:ps) = \w -> moveTo p w >> mapM_ (\p -> lineTo p w) ps
 over g1 g2     = \w -> g1 w >> g2 w
 drawInWindow   = id


Consciously excluding monads and restricting the design space to pure
functions is the basic tool of thought for finding such elegant
abstractions. As Paul Hudak said in his message "A regressive view of
support for imperative programming in Haskell"

  In my opinion one of the key principles in the design of Haskell has
  been the insistence on purity. It is arguably what led the Haskell
  designers to "discover" the monadic solution to IO, and is more
  generally what inspired many researchers to "discover" purely
  functional solutions to many seemingly imperative problems.

  http://article.gmane.org/gmane.comp.lang.haskell.cafe/27214

The philosophy of Haskell is that searching for purely functional
solution is well worth it.


Regards,
H. Apfelmus

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe