Re: [Haskell-cafe] Monad for HOAS?

2008-05-14 Thread Edsko de Vries
Hi,

On Wed, May 14, 2008 at 03:59:58PM +0300, Lauri Alanko wrote:
 On Wed, May 14, 2008 at 10:11:17AM +0100, Edsko de Vries wrote:
  Suppose we have some data structure that uses HOAS; typically, a DSL
  with explicit sharing. For example:
  
   data Expr = One | Add Expr Expr | Let Expr (Expr - Expr)
  
  When I use such a data structure, I find myself writing expressions such
  as
  
   Let foo $ \a - 
   Let bar $ \b -
   Add a b
  
  It seems to me that there should be a monad here somewhere, so that I
  can write this approximately like
  
  do a - foo
 b - bar
  return (Add a b)
 
 Neat idea, but the monad can't work exactly as you propose, because
 it'd break the monad laws: do { a - foo; return a } should be equal
 to foo, but in your example it'd result in Let foo id.
 
 However, with an explicit binding marker the continuation monad does
 what you want:
 
 import Control.Monad.Cont
 
 data Expr = One | Add Expr Expr | Let Expr (Expr - Expr)
 
 type ExprM = Cont Expr
 
 bind :: Expr - ExprM Expr
 bind e = Cont (Let e)
 
 runExprM :: ExprM Expr - Expr
 runExprM e = runCont e id
 
 Now you'd write your example as
 
 do a - bind foo
b - bind bar
return (Add a b)

Nice. That's certainly a step towards what I was looking for, although
it requires slightly more tags than I was hoping for :) But I've
incorporated it into my code and it's much better already :)

You mention that a direct implementation of what I suggested would
break the monad laws, as (foo) and (Let foo id) are not equal. But one
might argue that they are in fact, in a sense, equivalent. Do you reckon
that if it is acceptable that foo and do { a - foo; return a } don't
return equal terms (but equivalent terms), we can do still better?

Thanks again,

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


Re: [Haskell-cafe] Monad for HOAS?

2008-05-14 Thread Lauri Alanko
On Wed, May 14, 2008 at 03:59:23PM +0100, Edsko de Vries wrote:
 You mention that a direct implementation of what I suggested would
 break the monad laws, as (foo) and (Let foo id) are not equal. But one
 might argue that they are in fact, in a sense, equivalent. Do you reckon
 that if it is acceptable that foo and do { a - foo; return a } don't
 return equal terms (but equivalent terms), we can do still better?

If you just want the syntactic sugar and don't care about monads, in
GHC you can use plain do-notation:

{-# OPTIONS -fno-implicit-prelude #-}

import Prelude hiding ((=), fail)

data Expr = One | Add Expr Expr | Let Expr (Expr - Expr)

(=) = Let

fail = error

t :: Expr
t = do a - One
   b - Add a a
   Add b b

That's generally pretty icky, though.


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


Re: [Haskell-cafe] Monad for HOAS?

2008-05-14 Thread Conal Elliott
I share your perspective, Edsko.  If foo and (Let foo id) are
indistinguishable to clients of your module and are equal with respect to
your intended semantics of Exp, then I'd say at least this one monad law
holds.  - Conal

On Wed, May 14, 2008 at 7:59 AM, Edsko de Vries [EMAIL PROTECTED] wrote:

 Hi,

 On Wed, May 14, 2008 at 03:59:58PM +0300, Lauri Alanko wrote:
  On Wed, May 14, 2008 at 10:11:17AM +0100, Edsko de Vries wrote:
   Suppose we have some data structure that uses HOAS; typically, a DSL
   with explicit sharing. For example:
  
data Expr = One | Add Expr Expr | Let Expr (Expr - Expr)
  
   When I use such a data structure, I find myself writing expressions
 such
   as
  
Let foo $ \a -
Let bar $ \b -
Add a b
  
   It seems to me that there should be a monad here somewhere, so that I
   can write this approximately like
  
   do a - foo
  b - bar
   return (Add a b)
 
  Neat idea, but the monad can't work exactly as you propose, because
  it'd break the monad laws: do { a - foo; return a } should be equal
  to foo, but in your example it'd result in Let foo id.
 
  However, with an explicit binding marker the continuation monad does
  what you want:
 
  import Control.Monad.Cont
 
  data Expr = One | Add Expr Expr | Let Expr (Expr - Expr)
 
  type ExprM = Cont Expr
 
  bind :: Expr - ExprM Expr
  bind e = Cont (Let e)
 
  runExprM :: ExprM Expr - Expr
  runExprM e = runCont e id
 
  Now you'd write your example as
 
  do a - bind foo
 b - bind bar
 return (Add a b)

 Nice. That's certainly a step towards what I was looking for, although
 it requires slightly more tags than I was hoping for :) But I've
 incorporated it into my code and it's much better already :)

 You mention that a direct implementation of what I suggested would
 break the monad laws, as (foo) and (Let foo id) are not equal. But one
 might argue that they are in fact, in a sense, equivalent. Do you reckon
 that if it is acceptable that foo and do { a - foo; return a } don't
 return equal terms (but equivalent terms), we can do still better?

 Thanks again,

 Edsko
 ___
 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