[Template-haskell] quasi quotes and Q monad

Tomasz Zielonka tomasz.zielonka at gmail.com
Mon Jan 2 14:31:51 EST 2006


On Mon, Jan 02, 2006 at 07:36:03PM +0100, Ch. A. Herrmann wrote:
> Hi Tomasz,

Hi!

> >It seems that you are a bit confused with monads. The only monad you
> >have here is the Q type constructor. 
> >
> maybe you misunderstood me. Take the example of the ST monad. If you
> are in an ST monadic computation with state, then apply a non-monadic
> function in which you run a ST monad again, you are faced with two
> different states.

Well, yes, but that's because there is

    runST :: (forall s. ST s a) -> a

With Q there is no such function, or at least you are not supposed to
use it in normal code.

> As long as you finished the second monadic computation before you
> continue the first, this will not be a problem.  But if you are forced
> to insert a monadic value (not a return value) from the second
> activation into the first activation, you have two different states,
> and you have to consider how to proceed.  If you copy parts of the
> second activation into the first state, you'll have problem when you
> leave the second and continue the first activation. Thus, the only
> serious solution I can figure out at the moment is to ignore the state
> of the second activation when inserting a value from the second one in
> the first one.

The type of runST uses local universal quantification exactly to prevent
you from mixing things that belong to different State Threads. All ST
references, mutable arrays have a thread tag - that's what the 's' type
parameter is for.

> Coming back to the Q monad this would mean: ignore the name generation
> history from the point where the expression to be spliced was
> *created* and take the name generation history from the point where
> the splice is to be *inserted*, which is an older one. 

When you define

    var = [| $(liftM VarE (newName "a")) |]

there is no name generation history involved (at the place of
definition). This definition should be equivalent to

    var = liftM VarE (newName "a")

It is only when you actually run this code, for example in
a top-level splice, when the name generation history comes
into play.

Think of Q as

    type Q a = NameGenerationState -> (a, NameGenerationState)

Such a function can exist without NameGenerationState.
NameGenerationState is only neccesary when you want to compute the
result of such function, not when you are only using it to build more
and more complicated functions.

> Anyway, the names inside the generated splice take the newer
> information from the lexical scope of the creation.

I am not sure, but I think that lexical scopes in TH are implemented
indepentendly from name generation and the Q monad. Seems like I have to
read the TH papers again.

> However, I'm worried about that by turning an expression into a
> monadic form just by using *return* tags this splice with a blank name
> history and I hope that the quasi quote implementation will never
> proceed with this history but with the one from the lexical sope of
> the insertion point.

Monad laws state that "return" should be a pretty harmless function:

    (return x) >>= f == f x

    m >>= return == m
 
> Unfortunately, I've had too many bad experiences which make me feel
> not that optimistic, especially when working with state.

Could you describe your experiences in more detail? I can see that
playing with experimental stuff like Template Haskell or with
inherently unsafe features like the FFI can be less safe, but when you
exclude those, it's quite difficult to break things by accident,
or even on purpose!

Best regards
Tomasz

-- 
I am searching for a programmer who is good at least in some of
[Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland


More information about the template-haskell mailing list