[Haskell-cafe] I/O without monads, using an event loop

2008-05-30 Thread Robin Green
I have been thinking about to what extent you could cleanly do I/O
without explicit use of the I/O monad, and without uniqueness types
(which are the main alternative to monads in pure functional
programming, and are used in the Concurrent Clean programming language).

Suppose you have a main event handler function, like this:

eventMain :: (Event, SystemState AppState) - (Command, SystemState
AppState)

This function could be called over and over in an event loop, until an
EndProgram command was received, and the event loop would itself do all
the actual I/O (the SystemStates are only in-memory representations of
some part of the system state, plus the application's own state). Things
like disk I/O could be done with commands which generate events when
complete. Interprocess communication could be done in the same way.

Then eventMain, and everything called by it, would be
referentially-transparent, and yet non-monadic. You could of course
build higher-level stuff on top of that.

On the other hand, it's quite stateful, because anything you need to
remember between events need to be recorded, either in the SystemState
or externally (e.g. in a file). I suppose this is the most important
disadvantage?

Is there any published work or code using this approach, or something
like it, in a pure functional language? I'm primarily interested in
embedded system and desktop UIs, rather than say web-based systems,
although both would be interesting.

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


Re: [Haskell-cafe] I/O without monads, using an event loop

2008-05-30 Thread Edsko de Vries
On Fri, May 30, 2008 at 03:09:37PM +0100, Robin Green wrote:
 I have been thinking about to what extent you could cleanly do I/O
 without explicit use of the I/O monad, and without uniqueness types
 (which are the main alternative to monads in pure functional
 programming, and are used in the Concurrent Clean programming language).
 
 Suppose you have a main event handler function, like this:
 
 eventMain :: (Event, SystemState AppState) - (Command, SystemState
 AppState)
 
 This function could be called over and over in an event loop, until an
 EndProgram command was received, and the event loop would itself do all
 the actual I/O (the SystemStates are only in-memory representations of
 some part of the system state, plus the application's own state). Things
 like disk I/O could be done with commands which generate events when
 complete. Interprocess communication could be done in the same way.
 
 Then eventMain, and everything called by it, would be
 referentially-transparent, and yet non-monadic. You could of course
 build higher-level stuff on top of that.
 
 On the other hand, it's quite stateful, because anything you need to
 remember between events need to be recorded, either in the SystemState
 or externally (e.g. in a file). I suppose this is the most important
 disadvantage?
 
 Is there any published work or code using this approach, or something
 like it, in a pure functional language? I'm primarily interested in
 embedded system and desktop UIs, rather than say web-based systems,
 although both would be interesting.

Yeah, check the History of Haskell paper, in particular Section 7.

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


Re: [Haskell-cafe] I/O without monads, using an event loop

2008-05-30 Thread Andrew Butterfield

Robin Green wrote:

I have been thinking about to what extent you could cleanly do I/O
without explicit use of the I/O monad, and without uniqueness types
(which are the main alternative to monads in pure functional
programming, and are used in the Concurrent Clean programming language).

Suppose you have a main event handler function, like this:

eventMain :: (Event, SystemState AppState) - (Command, SystemState
AppState)

This function could be called over and over in an event loop, until an
EndProgram command was received, and the event loop would itself do all
the actual I/O (the SystemStates are only in-memory representations of
some part of the system state, plus the application's own state). Things
like disk I/O could be done with commands which generate events when
complete. Interprocess communication could be done in the same way.

Then eventMain, and everything called by it, would be
referentially-transparent, and yet non-monadic. You could of course
build higher-level stuff on top of that.
  
Given the above, without uniqueness typing, and because there is clearly 
no monad,

I could write

breakMain
:: (Event,Event,SystemState AppState)
 - ((Command,SystemState AppState),(Command,SystemState AppState))
breakMain (e1,e2,sys) = ( eventMain (e1,sys) , eventMain (e2,sys) )

Now what happens? Do we get two copies of SystemState ?

Simpler still, I can write  (sys,eventMain e sys) -- what happens here?
I have references to both before- and after- state.

It is this probelm with copying the un-copiable (external I/O state),
that requires pure functional languages to outlaw such programs,
either via uniqueness typing, or via a monad interface that completely
hides any direct reference to the underlying state and which
then sequences the application of state transformers.
  



--

Andrew Butterfield Tel: +353-1-896-2517 Fax: +353-1-677-2204
Foundations and Methods Research Group Director.
School of Computer Science and Statistics,
Room F.13, O'Reilly Institute, Trinity College, University of Dublin
   http://www.cs.tcd.ie/Andrew.Butterfield/


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


Re: [Haskell-cafe] I/O without monads, using an event loop

2008-05-30 Thread Robin Green
On Fri, 30 May 2008 15:23:46 +0100
Andrew Butterfield [EMAIL PROTECTED] wrote:

 Robin Green wrote:
  I have been thinking about to what extent you could cleanly do I/O
  without explicit use of the I/O monad, and without uniqueness types
  (which are the main alternative to monads in pure functional
  programming, and are used in the Concurrent Clean programming
  language).
 
  Suppose you have a main event handler function, like this:
 
  eventMain :: (Event, SystemState AppState) - (Command, SystemState
  AppState)
 
  This function could be called over and over in an event loop, until
  an EndProgram command was received, and the event loop would itself
  do all the actual I/O (the SystemStates are only in-memory
  representations of some part of the system state, plus the
  application's own state). Things like disk I/O could be done with
  commands which generate events when complete. Interprocess
  communication could be done in the same way.
 
  Then eventMain, and everything called by it, would be
  referentially-transparent, and yet non-monadic. You could of course
  build higher-level stuff on top of that.

 Given the above, without uniqueness typing, and because there is
 clearly no monad,
 I could write
 
 breakMain
  :: (Event,Event,SystemState AppState)
   - ((Command,SystemState AppState),(Command,SystemState AppState))
 breakMain (e1,e2,sys) = ( eventMain (e1,sys) , eventMain (e2,sys) )
 
 Now what happens? Do we get two copies of SystemState ?
 
 Simpler still, I can write  (sys,eventMain e sys) -- what happens
 here? I have references to both before- and after- state.

Yes, you do - but they're only in-memory representations. Sorry, I
didn't fully explain what I meant. Two points:

1. The SystemState record only contains in-memory representations of
*some* parts of the system state - e.g. on an embedded system they could
be the on/off status of the LEDs, motor speeds, the state of the toggle
switches, which buttons are currently being pressed, etc. It would be
infeasible to record the entire state of, say, an attached 120GB hard
drive - and even less feasible to record the state of the external
environment - so only some parts of the system would be covered by this
data structure.

2. It's the event loop's job to do any necessary I/O to update the
*actual* system state to match the SystemState returned by eventMain
(ignoring any changes which are impossible, e.g. if the program tries
to say a toggle switch is on when it isn't). As I said, only in the
event loop is any I/O actually performed.

So when you evaluate breakMain or whatever, nothing happens - it's
just manipulating representations. You can only return one SystemState
from eventMain, and that is used to update the real system state - so
there's no paradox.
-- 
Robin
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] I/O without monads, using an event loop

2008-05-30 Thread Wolfgang Jeltsch
Am Freitag, 30. Mai 2008 16:09 schrieb Robin Green:
 […]

 I'm primarily interested in embedded system and desktop UIs,

Than you should take a look at http://haskell.org/haskellwiki/FRP.

 […]

Best wishes,
Wolfgang
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] I/O without monads, using an event loop

2008-05-30 Thread Jake Mcarthur

On May 30, 2008, at 9:09 AM, Robin Green wrote:

eventMain :: (Event, SystemState AppState) - (Command, SystemState  
AppState)


The first thing I would do with this type is probably wrap it up in a  
State monad so I don't have to keep track of the SystemState AppState  
stuff myself, which completely defeats the purpose. I don't think this  
really makes anything simpler at all.


Also see FRP for a perhaps more practical way of approaching IO as  
event streams.


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


Re: [Haskell-cafe] I/O without monads, using an event loop

2008-05-30 Thread Roberto Zunino
Robin Green wrote:
 I have been thinking about to what extent you could cleanly do I/O
 without explicit use of the I/O monad, and without uniqueness types

Here's a way to see I/O as a pure functional data structure. To keep
things simple, we model only Char I/O:

data Program
  = Quit
  | Output Char Program
  | Input (Char - Program)
  -- ... add here other I/O primitives if you want

-- Example:
cat :: Program
cat = Input (\c - Output c cat)

-- Trivial mapping into the IO monad
runProgram :: Program - IO ()
runProgram Quit = return ()
runProgram (Output c p) = putChar c  runProgram p
runProgram (Input k)= getChar = runProgram . k

Another approach could be to use lazy I/O, à la interact. However, I am
uncomfortable with lazy I/O.

See also IOSpec, a nice functional model of the IO monad:

  http://www.cs.nott.ac.uk/~wss/repos/IOSpec/

Regards,
Zun.
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] I/O without monads, using an event loop

2008-05-30 Thread Bit Connor
Yeah, this sounds really similar to functionally reactive programming.

I recommend you start by reading this paper:

http://haskell.cs.yale.edu/frp/genuinely-functional-guis.pdf

On Fri, May 30, 2008 at 11:34 AM, Wolfgang Jeltsch
[EMAIL PROTECTED] wrote:
 Am Freitag, 30. Mai 2008 16:09 schrieb Robin Green:
 […]

 I'm primarily interested in embedded system and desktop UIs,

 Than you should take a look at http://haskell.org/haskellwiki/FRP.

 […]

 Best wishes,
 Wolfgang
 ___
 Haskell-Cafe mailing list
 Haskell-Cafe@haskell.org
 http://www.haskell.org/mailman/listinfo/haskell-cafe

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