<div class="gmail_quote">On Fri, Aug 21, 2009 at 5:03 AM, David Menendez <span dir="ltr"><<a href="mailto:dave@zednenem.com">dave@zednenem.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">On Thu, Aug 20, 2009 at 6:57 PM, Peter Verswyvelen<<a href="mailto:bugfact@gmail.com">bugfact@gmail.com</a>> wrote:<br>
><br>
> On Thu, Aug 20, 2009 at 11:23 PM, David Menendez <<a href="mailto:dave@zednenem.com">dave@zednenem.com</a>> wrote:<br>
>><br>
>> The important things to note are (1) getChar# depends on the token<br>
>> returned by putChar#, thus guaranteeing that putChar# gets executed<br>
>> first, and (2) putChar# and getChar# are impure and cannot normally be<br>
>> defined in Haskell.<br>
><br>
> Ok, that I understand. But if getChar# and putChar# would be pure functions<br>
> that just generate some output string / consume some input string, then this<br>
> realworld token passing would not work when used with interact, since<br>
> neither the output or input string really depends on the dummy token, unless<br>
> using a seq again (or strictness annotation, which was explained to be just<br>
> syntactic sugar for seq)?<br>
<br>
</div>I'm not sure I understand your question, but I think it's possible to<br>
use interact in the way you want. For example, this code behaves<br>
correctly for me:<br>
<br>
foo i =<br>
let i1 = lines i<br>
in "Enter your name: " ++<br>
(case i1 of<br>
[] -> error "EOF"<br>
name:i2 -> "Welcome " ++ name ++ "\n")<br>
<br>
Prelude> interact foo<br>
Enter your name: Bob<br>
Welcome Bob</blockquote><div><br></div><div>Yes but this also enforce strictness, since you're pattern matching against the input, forcing it to be evaluated. If for example the empty string would be valid input, this wouldn't work, and seq would be needed again no?</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">Note the dependencies here. When you call interact foo, the prompt can<br>
be immediately output without reading any of the input. However,<br>
"Welcome" cannot be printed until one line of the input has been read<br>
(or EOF reached) because it's inside the pattern match on i1.<br>
<div class="im"><br>
<br>
> But how would we then make a pure monad that can<br>
> be used as in my example together with interact? I see no reason why to put<br>
> everything in IO when it just comes to converting a stream of inputs to a<br>
> stream of outputs? So interact really is useless, unless you just fmap<br>
> something over the input or when the output is independent from the input?<br>
<br>
</div>Not necessarily. Your situation reminds me of Haskell's I/O system<br>
before the IO monad was introduced. (See section 7 of "A History of<br>
Haskell: Being Lazy With Class" for details.<br>
<<a href="http://research.microsoft.com/en-us/um/people/simonpj/papers/history-of-haskell/history.pdf" target="_blank">http://research.microsoft.com/en-us/um/people/simonpj/papers/history-of-haskell/history.pdf</a>>)<br>
<br>
In it, they describe how older versions of Haskell could be defined in<br>
terms of lazy request and response streams, how you can use<br>
continuation-passing to build the streams in a more localized way, and<br>
then how you could define the IO monad in terms of that.<br>
<br>
This works for me:<br>
<br>
import Control.Monad.Cont<br>
<br>
type Behavior = [String] -> String<br>
type MyIO = Cont Behavior<br>
<br>
putLine :: String -> MyIO ()<br>
putLine s = Cont $ \k ss -> s ++ k () ss<br>
<br>
getLine :: MyIO String<br>
getLine = Cont $ \k (s:ss) -> k s ss<br>
<br>
run :: MyIO () -> Behavior<br>
run m = runCont m (\_ _ -> [])<br>
<br>
foo = do<br>
putLine "Enter name: "<br>
name <- getLine<br>
putLine ("Welcome " ++ name ++ "\n")<br>
<br>
Prelude Control.Monad.Cont> interact (run foo . lines)<br>
Enter name: Dave<br>
Welcome Dave<br>
<br>
It may be instructive to manually expand "run foo".</blockquote><div><br></div><div>This suffers from the same strictness problem on the input, e.g. when making getLine less strict, as in: </div><div><br></div>
<div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;">import Prelude hiding (getLine)</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;">import Control.Monad.Cont</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"><br></span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;">type Behavior = [String] -> String</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;">type MyIO = Cont Behavior</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"><br>
</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;">putLine :: String -> MyIO ()</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;">putLine s = Cont $ \k ss -> s ++ k () ss</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"><br></span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;">getLine :: MyIO String</span></font></div>
<div><font class="Apple-style-span" face="'courier new'" size="4"><span class="Apple-style-span" style="font-size: 16px;">-- Was: getLine = Cont $ \k <b>(s:ss) -> k s ss</b></span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large; "><b><font class="Apple-style-span" color="#009900">getLine = Cont $ \k ss -> k (head ss) (tail ss)</font></b></span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"><br></span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;">run :: MyIO () -> Behavior</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;">run m = runCont m (\_ _ -> [])</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"><br>
</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;">foo = do</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> putLine "Enter name: "</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> name <- getLine</span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"> putLine ("Welcome " ++ name ++ "\n")</span></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;"><br></span></font></div><div><font class="Apple-style-span" face="'courier new', monospace"><span class="Apple-style-span" style="font-size: large;">main = interact (run foo . lines)</span></font></div>
<div><br></div><div>You get the "Welcome" before the name again.</div><div><br></div><div>To be honest I don't fully understand why this is a horrible hack. From a pure point of view, the behavior is the same, weither or not the input is made strict. When side effects are present (interactive input/output from the user), it does matter, but aren't all space/time leaks to be considered as some sort of "operational effects"? In a pure mathematical world, space and time leaks would not really matter?</div>
<div><br></div><div>I do understand much more now, thanks. The best solution for making this IO pure remains MonadPrompt I guess.</div><div><br></div><div>Too bad that something extremely simple like console text IO doesn't seem to be a good start for introducing FRP, or maybe seen from another angle (using Reactive) it might still be, dono</div>
<div><br></div></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"><br>
<font color="#888888"><br>
--<br>
</font><div><div></div><div class="h5">Dave Menendez <<a href="mailto:dave@zednenem.com">dave@zednenem.com</a>><br>
<<a href="http://www.eyrie.org/~zednenem/" target="_blank">http://www.eyrie.org/~zednenem/</a>><br>
</div></div></blockquote></div><br>