You're correct, you cannot simply thread a function into a computational expression.<div>As you mentioned, the expansion only happens with the known syntatic forms.</div><div>One obvious one is <font face="'courier new', monospace">return</font> which gets desugared to a call to the <font face="'courier new', monospace">Return</font> method on the builder object.</div>
<div><br></div><div>However, you could do:</div><div><br></div><div><font class="Apple-style-span" face="'courier new', monospace">let myReturn x = return x;;</font></div><div><font class="Apple-style-span" face="'courier new', monospace">parse { let! t = token</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> return! myReturn t }</font></div><div><br></div><div>(note: <font class="Apple-style-span" face="'courier new', monospace">return!</font> gets transformed into a call to <font class="Apple-style-span" face="'courier new', monospace">ReturnFrom</font> on the builder object)</div>
<div><br></div><div>but this is quite ugly IMO.</div><div><br></div>
<div>More interesting is that you could use inheritance to extend the expression builder.</div><div>For example:</div><div><br></div><div><div><font class="Apple-style-span" face="'courier new', monospace">let bind m f = f (m ())</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace">let return' v = fun () -> v</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">type ParserBuilder() = </font></div><div><font class="Apple-style-span" face="'courier new', monospace"> member this.Bind(m,f) = bind m f</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> abstract member Return : int -> (unit -> int)</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> default this.Return(x) = return' x</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font>
</div><div><font class="Apple-style-span" face="'courier new', monospace">let parse = ParserBuilder()</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div>
<font class="Apple-style-span" face="'courier new', monospace">let fx = </font></div><div><font class="Apple-style-span" face="'courier new', monospace"> parse { let! t = return' 4 </font></div><div>
<font class="Apple-style-span" face="'courier new', monospace"> return t}</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">printfn "%i" (fx())</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">let myReturn x = return' (4*x)</font></div><div>
<font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">type MyParserBuilder() =</font></div><div><font class="Apple-style-span" face="'courier new', monospace"> inherit ParserBuilder()</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> override this.Return(x) = myReturn x</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div>
<div><font class="Apple-style-span" face="'courier new', monospace">let myParse = MyParserBuilder()</font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">let myfx = </font></div><div><font class="Apple-style-span" face="'courier new', monospace"> myParse { let! t = return' 4 </font></div>
<div><font class="Apple-style-span" face="'courier new', monospace"> return t}</font></div><div><font class="Apple-style-span" face="'courier new', monospace"><br></font></div><div><font class="Apple-style-span" face="'courier new', monospace">printfn "%i" (myfx())</font></div>
</div><div><br></div><div>which gets you almost the same abstraction, right?</div><div><br></div><div>-- <br>Jake<br><br>
<div class="gmail_quote">
On Tue, Mar 16, 2010 at 4:03 PM, John Clements <span dir="ltr"><<a href="mailto:clements@brinckerhoff.org" target="_blank">clements@brinckerhoff.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Which is better? Haskell or F#?<br>
<br>
Wait, wait, no, that's not what I meant at all.<br>
<br>
I was reading up on F#'s computational expressions last night, and I'm impressed by their flexibility. I do see one teeny tiny thing that's missing, though.<br>
<br>
In particular, it looks like computation expressions (e.g.<br>
<br>
parse { let! e = token<br>
return e}<br>
<br>
Are a lot like Haskell's monads. In fact, in one way they're nicer; rather than just bind and return, you get a whole bunch of syntactic forms that you can redefine.<br>
<br>
But! If I understand correctly, these overridings happen only within the syntactic boundaries of the curly braces, right? So you couldn't abstract over those pieces in quite the same way.<br>
<br>
E.G:<br>
<br>
let myReturn x = return x;;<br>
<br>
parse { let! t = token<br>
myReturn t}<br>
<br>
... wouldn't work, right?<br>
<br>
Whereas Haskell gets it right:<br>
<br>
myReturn = return<br>
<br>
p = do t <- token<br>
myReturn t<br>
<br>
<br>
<br>
I haven't tried actually running any of this, mind you. Of course, Scheme can't do this, either; it's a consequence of Haskell's truly insane type system.<br>
<font color="#888888"><br>
<br>
John<br><font class="Apple-style-span" color="#000000"><font class="Apple-style-span" color="#888888"><br></font></font></font></blockquote></div>
</div>