Why are nested brackets disallowed?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Why are nested brackets disallowed?

Matthew Pickering
There is a check in `RnSplice` which errors on the following program
with nested brackets.

```
prog = [| [| True |] |]

T.hs:4:11: error:
    • Template Haskell brackets cannot be nested (without intervening splices)
    • In the Template Haskell quotation [| True |]
      In the Template Haskell quotation [| [| True |] |]
  |
4 | prog = [| [| True |] |]
  |           ^^^^^^^^^^

```

As far as I can see the check was added in 2013 in this commit,
https://github.com/ghc/ghc/commit/d0d47ba76f8f0501cf3c4966bc83966ab38cac27#diff-58794f81a415f148d011de563988c2b5R170

But there is no note, no tests and no comment about why it was added.

I removed the check and added a `BracketE` constructor to the
template-haskell AST and the
code compiles fine.

I can also construct a program which needs to be spliced twice and
this also works fine.

```
func Add = [| (+) |]
func Mul = [| (*) |]

f1 "+" = [| Add |]
f1 "*" = [| Mul |]

comb s = [| func $(f1 s) |]
```
```
res = $($(comb "*"))
```

So it seems the restriction is quite arbitrary but I was wondering if
I was missing some limitation which meant this check was added. I
would not be surprised if something more complicated goes wrong with
splicing.

Cheers,

Matt
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Why are nested brackets disallowed?

Ben Gamari-2
Matthew Pickering <[hidden email]> writes:

> There is a check in `RnSplice` which errors on the following program
> with nested brackets.
>
It might be good to explicitly include Geoff Mainland in this thread.
I'm not sure he'll see it otherwise.

Cheers,

- Ben


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

signature.asc (497 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Why are nested brackets disallowed?

Richard Eisenberg-4
I think Geoff was primarily concerned with typed Template Haskell, not the untyped variety.

I, too, have wondered if there was a technical reason behind this restriction, or if merely it was assumed that nested brackets were not worthwhile.

One question: how would staging work between nesting levels of brackets?

Richard

> On Jan 24, 2019, at 12:42 PM, Ben Gamari <[hidden email]> wrote:
>
> Matthew Pickering <[hidden email]> writes:
>
>> There is a check in `RnSplice` which errors on the following program
>> with nested brackets.
>>
> It might be good to explicitly include Geoff Mainland in this thread.
> I'm not sure he'll see it otherwise.
>
> Cheers,
>
> - Ben
>
> _______________________________________________
> ghc-devs mailing list
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Why are nested brackets disallowed?

Matthew Pickering
I don't think that cross stage persistence will work as it is
currently implemented which is probably why the check exists.

1. The normal case

foo x = [| x |] ===>
  foo x = [| $(lift x) |]

2. x is defined at stage 0, and used at stage 2.

One option is:
foo x = [| [| x |] |] ===>
  foo x = [| [| $($(lift (lift x))) |] |]
or
foo x = [| [| x |] |] ===>
  foo x = [| let x' = $(lift x) in [| $(lift [| x' |]) |]

We need to think a bit how to `lift` something of type `Q Exp` because
of the `Q` monad. Lifting an `Exp` seems trivial as it's a normal ADT
(I tested and this works after deriving 40 instances).

You can define `lift2` which lifts an expression twice as follows.

```
lift2 :: Lift a => a -> Q Exp
lift2 a = lift a >>= \e -> [| return $ $(lift e) |]
```

3. x is defined at stage 1 and used in stage 2

foo = [| \x -> [| x |] |] ===>
  foo = [| \x -> [| $(lift x) |] |]

Desugared with a single call to `lift` like normal.

4. x is defined in stage 2 and used in stage 1

foo = [| [| \x -> $(x) |] |]

Rejected just like usual. `x` won't be bound when the splice is run.

It seems that with some suitable care that things will work out when
lifting across multiple levels but that is the point where care needs
to be taken.

Matt



On Thu, Jan 24, 2019 at 5:46 PM Richard Eisenberg <[hidden email]> wrote:

>
> I think Geoff was primarily concerned with typed Template Haskell, not the untyped variety.
>
> I, too, have wondered if there was a technical reason behind this restriction, or if merely it was assumed that nested brackets were not worthwhile.
>
> One question: how would staging work between nesting levels of brackets?
>
> Richard
>
> > On Jan 24, 2019, at 12:42 PM, Ben Gamari <[hidden email]> wrote:
> >
> > Matthew Pickering <[hidden email]> writes:
> >
> >> There is a check in `RnSplice` which errors on the following program
> >> with nested brackets.
> >>
> > It might be good to explicitly include Geoff Mainland in this thread.
> > I'm not sure he'll see it otherwise.
> >
> > Cheers,
> >
> > - Ben
> >
> > _______________________________________________
> > ghc-devs mailing list
> > [hidden email]
> > http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

RE: Why are nested brackets disallowed?

GHC - devs mailing list
Interesting. I don’t recall a specific reason why nested brackets were outlawed. I think it was just that we didn't think we needed them, so it seemed simplest not to have them.  TH does not do runtime codegen, so there are really only two stages: compile time and run time.

Do you have a compelling use-case?

Simon

|  -----Original Message-----
|  From: ghc-devs <[hidden email]> On Behalf Of Matthew
|  Pickering
|  Sent: 25 January 2019 11:57
|  To: Richard Eisenberg <[hidden email]>
|  Cc: GHC developers <[hidden email]>
|  Subject: Re: Why are nested brackets disallowed?
|  
|  I don't think that cross stage persistence will work as it is currently
|  implemented which is probably why the check exists.
|  
|  1. The normal case
|  
|  foo x = [| x |] ===>
|    foo x = [| $(lift x) |]
|  
|  2. x is defined at stage 0, and used at stage 2.
|  
|  One option is:
|  foo x = [| [| x |] |] ===>
|    foo x = [| [| $($(lift (lift x))) |] |] or foo x = [| [| x |] |] ===>
|    foo x = [| let x' = $(lift x) in [| $(lift [| x' |]) |]
|  
|  We need to think a bit how to `lift` something of type `Q Exp` because of
|  the `Q` monad. Lifting an `Exp` seems trivial as it's a normal ADT (I
|  tested and this works after deriving 40 instances).
|  
|  You can define `lift2` which lifts an expression twice as follows.
|  
|  ```
|  lift2 :: Lift a => a -> Q Exp
|  lift2 a = lift a >>= \e -> [| return $ $(lift e) |] ```
|  
|  3. x is defined at stage 1 and used in stage 2
|  
|  foo = [| \x -> [| x |] |] ===>
|    foo = [| \x -> [| $(lift x) |] |]
|  
|  Desugared with a single call to `lift` like normal.
|  
|  4. x is defined in stage 2 and used in stage 1
|  
|  foo = [| [| \x -> $(x) |] |]
|  
|  Rejected just like usual. `x` won't be bound when the splice is run.
|  
|  It seems that with some suitable care that things will work out when
|  lifting across multiple levels but that is the point where care needs to
|  be taken.
|  
|  Matt
|  
|  
|  
|  On Thu, Jan 24, 2019 at 5:46 PM Richard Eisenberg <[hidden email]>
|  wrote:
|  >
|  > I think Geoff was primarily concerned with typed Template Haskell, not
|  the untyped variety.
|  >
|  > I, too, have wondered if there was a technical reason behind this
|  restriction, or if merely it was assumed that nested brackets were not
|  worthwhile.
|  >
|  > One question: how would staging work between nesting levels of
|  brackets?
|  >
|  > Richard
|  >
|  > > On Jan 24, 2019, at 12:42 PM, Ben Gamari <[hidden email]>
|  wrote:
|  > >
|  > > Matthew Pickering <[hidden email]> writes:
|  > >
|  > >> There is a check in `RnSplice` which errors on the following
|  > >> program with nested brackets.
|  > >>
|  > > It might be good to explicitly include Geoff Mainland in this thread.
|  > > I'm not sure he'll see it otherwise.
|  > >
|  > > Cheers,
|  > >
|  > > - Ben
|  > >
|  > > _______________________________________________
|  > > ghc-devs mailing list
|  > > [hidden email]
|  > > https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmai
|  > > l.haskell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fghc-devs&amp;data=02%
|  > > 7C01%7Csimonpj%40microsoft.com%7Cdf0aa539bb1041dca42308d682bc3d4b%7C
|  > > 72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636840142327169830&amp;sd
|  > > ata=oIiA768uqGGGBJh7ogpymmPvuKBDLj%2BiqJCZpig6SPg%3D&amp;reserved=0
|  >
|  _______________________________________________
|  ghc-devs mailing list
|  [hidden email]
|  https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmail.has
|  kell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fghc-
|  devs&amp;data=02%7C01%7Csimonpj%40microsoft.com%7Cdf0aa539bb1041dca42308d
|  682bc3d4b%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636840142327169830
|  &amp;sdata=oIiA768uqGGGBJh7ogpymmPvuKBDLj%2BiqJCZpig6SPg%3D&amp;reserved=
|  0
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Why are nested brackets disallowed?

Richard Eisenberg-4
In reply to this post by Matthew Pickering
This typechecks:

instance Lift a => Lift (Q a) where
  lift :: Q a -> Q Exp
  lift x = join (fmap lift x)

And it looks correct. Do you agree?

In general, it sounds like you've thought this through. To me, this doesn't rise to the need of a ghc-proposal; I would say to go for it.

Richard

> On Jan 25, 2019, at 6:56 AM, Matthew Pickering <[hidden email]> wrote:
>
> I don't think that cross stage persistence will work as it is
> currently implemented which is probably why the check exists.
>
> 1. The normal case
>
> foo x = [| x |] ===>
>  foo x = [| $(lift x) |]
>
> 2. x is defined at stage 0, and used at stage 2.
>
> One option is:
> foo x = [| [| x |] |] ===>
>  foo x = [| [| $($(lift (lift x))) |] |]
> or
> foo x = [| [| x |] |] ===>
>  foo x = [| let x' = $(lift x) in [| $(lift [| x' |]) |]
>
> We need to think a bit how to `lift` something of type `Q Exp` because
> of the `Q` monad. Lifting an `Exp` seems trivial as it's a normal ADT
> (I tested and this works after deriving 40 instances).
>
> You can define `lift2` which lifts an expression twice as follows.
>
> ```
> lift2 :: Lift a => a -> Q Exp
> lift2 a = lift a >>= \e -> [| return $ $(lift e) |]
> ```
>
> 3. x is defined at stage 1 and used in stage 2
>
> foo = [| \x -> [| x |] |] ===>
>  foo = [| \x -> [| $(lift x) |] |]
>
> Desugared with a single call to `lift` like normal.
>
> 4. x is defined in stage 2 and used in stage 1
>
> foo = [| [| \x -> $(x) |] |]
>
> Rejected just like usual. `x` won't be bound when the splice is run.
>
> It seems that with some suitable care that things will work out when
> lifting across multiple levels but that is the point where care needs
> to be taken.
>
> Matt
>
>
>
> On Thu, Jan 24, 2019 at 5:46 PM Richard Eisenberg <[hidden email]> wrote:
>>
>> I think Geoff was primarily concerned with typed Template Haskell, not the untyped variety.
>>
>> I, too, have wondered if there was a technical reason behind this restriction, or if merely it was assumed that nested brackets were not worthwhile.
>>
>> One question: how would staging work between nesting levels of brackets?
>>
>> Richard
>>
>>> On Jan 24, 2019, at 12:42 PM, Ben Gamari <[hidden email]> wrote:
>>>
>>> Matthew Pickering <[hidden email]> writes:
>>>
>>>> There is a check in `RnSplice` which errors on the following program
>>>> with nested brackets.
>>>>
>>> It might be good to explicitly include Geoff Mainland in this thread.
>>> I'm not sure he'll see it otherwise.
>>>
>>> Cheers,
>>>
>>> - Ben
>>>
>>> _______________________________________________
>>> ghc-devs mailing list
>>> [hidden email]
>>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>>

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Why are nested brackets disallowed?

Matthew Pickering
In reply to this post by GHC - devs mailing list
It's possible to have multiple compile time phases (as evidenced by
the possibility of multiple splices). Metaocaml supports k phases so
we should as well!

Fwiw, It is also possible to implement run-time code generation, see

https://github.com/mainland/th-new
http://johnlato.blogspot.com/2012/10/runtime-meta-programming-in-haskell.html

On Fri, Jan 25, 2019 at 12:49 PM Simon Peyton Jones
<[hidden email]> wrote:

>
> Interesting. I don’t recall a specific reason why nested brackets were outlawed. I think it was just that we didn't think we needed them, so it seemed simplest not to have them.  TH does not do runtime codegen, so there are really only two stages: compile time and run time.
>
> Do you have a compelling use-case?
>
> Simon
>
> |  -----Original Message-----
> |  From: ghc-devs <[hidden email]> On Behalf Of Matthew
> |  Pickering
> |  Sent: 25 January 2019 11:57
> |  To: Richard Eisenberg <[hidden email]>
> |  Cc: GHC developers <[hidden email]>
> |  Subject: Re: Why are nested brackets disallowed?
> |
> |  I don't think that cross stage persistence will work as it is currently
> |  implemented which is probably why the check exists.
> |
> |  1. The normal case
> |
> |  foo x = [| x |] ===>
> |    foo x = [| $(lift x) |]
> |
> |  2. x is defined at stage 0, and used at stage 2.
> |
> |  One option is:
> |  foo x = [| [| x |] |] ===>
> |    foo x = [| [| $($(lift (lift x))) |] |] or foo x = [| [| x |] |] ===>
> |    foo x = [| let x' = $(lift x) in [| $(lift [| x' |]) |]
> |
> |  We need to think a bit how to `lift` something of type `Q Exp` because of
> |  the `Q` monad. Lifting an `Exp` seems trivial as it's a normal ADT (I
> |  tested and this works after deriving 40 instances).
> |
> |  You can define `lift2` which lifts an expression twice as follows.
> |
> |  ```
> |  lift2 :: Lift a => a -> Q Exp
> |  lift2 a = lift a >>= \e -> [| return $ $(lift e) |] ```
> |
> |  3. x is defined at stage 1 and used in stage 2
> |
> |  foo = [| \x -> [| x |] |] ===>
> |    foo = [| \x -> [| $(lift x) |] |]
> |
> |  Desugared with a single call to `lift` like normal.
> |
> |  4. x is defined in stage 2 and used in stage 1
> |
> |  foo = [| [| \x -> $(x) |] |]
> |
> |  Rejected just like usual. `x` won't be bound when the splice is run.
> |
> |  It seems that with some suitable care that things will work out when
> |  lifting across multiple levels but that is the point where care needs to
> |  be taken.
> |
> |  Matt
> |
> |
> |
> |  On Thu, Jan 24, 2019 at 5:46 PM Richard Eisenberg <[hidden email]>
> |  wrote:
> |  >
> |  > I think Geoff was primarily concerned with typed Template Haskell, not
> |  the untyped variety.
> |  >
> |  > I, too, have wondered if there was a technical reason behind this
> |  restriction, or if merely it was assumed that nested brackets were not
> |  worthwhile.
> |  >
> |  > One question: how would staging work between nesting levels of
> |  brackets?
> |  >
> |  > Richard
> |  >
> |  > > On Jan 24, 2019, at 12:42 PM, Ben Gamari <[hidden email]>
> |  wrote:
> |  > >
> |  > > Matthew Pickering <[hidden email]> writes:
> |  > >
> |  > >> There is a check in `RnSplice` which errors on the following
> |  > >> program with nested brackets.
> |  > >>
> |  > > It might be good to explicitly include Geoff Mainland in this thread.
> |  > > I'm not sure he'll see it otherwise.
> |  > >
> |  > > Cheers,
> |  > >
> |  > > - Ben
> |  > >
> |  > > _______________________________________________
> |  > > ghc-devs mailing list
> |  > > [hidden email]
> |  > > https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmai
> |  > > l.haskell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fghc-devs&amp;data=02%
> |  > > 7C01%7Csimonpj%40microsoft.com%7Cdf0aa539bb1041dca42308d682bc3d4b%7C
> |  > > 72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636840142327169830&amp;sd
> |  > > ata=oIiA768uqGGGBJh7ogpymmPvuKBDLj%2BiqJCZpig6SPg%3D&amp;reserved=0
> |  >
> |  _______________________________________________
> |  ghc-devs mailing list
> |  [hidden email]
> |  https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmail.has
> |  kell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fghc-
> |  devs&amp;data=02%7C01%7Csimonpj%40microsoft.com%7Cdf0aa539bb1041dca42308d
> |  682bc3d4b%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C636840142327169830
> |  &amp;sdata=oIiA768uqGGGBJh7ogpymmPvuKBDLj%2BiqJCZpig6SPg%3D&amp;reserved=
> |  0
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Why are nested brackets disallowed?

Matthew Pickering
In reply to this post by Richard Eisenberg-4
That definition typechecks but doesn't do what you intend I think.

If you `lift (lift Bool)` then result of splicing this is of type
`Exp` and not `Q Exp` as you intended so you can't splice it again.

That is why my definition is more complicated and involves `return`.

Cheers,

Matt

On Fri, Jan 25, 2019 at 12:50 PM Richard Eisenberg <[hidden email]> wrote:

>
> This typechecks:
>
> instance Lift a => Lift (Q a) where
>   lift :: Q a -> Q Exp
>   lift x = join (fmap lift x)
>
> And it looks correct. Do you agree?
>
> In general, it sounds like you've thought this through. To me, this doesn't rise to the need of a ghc-proposal; I would say to go for it.
>
> Richard
>
> > On Jan 25, 2019, at 6:56 AM, Matthew Pickering <[hidden email]> wrote:
> >
> > I don't think that cross stage persistence will work as it is
> > currently implemented which is probably why the check exists.
> >
> > 1. The normal case
> >
> > foo x = [| x |] ===>
> >  foo x = [| $(lift x) |]
> >
> > 2. x is defined at stage 0, and used at stage 2.
> >
> > One option is:
> > foo x = [| [| x |] |] ===>
> >  foo x = [| [| $($(lift (lift x))) |] |]
> > or
> > foo x = [| [| x |] |] ===>
> >  foo x = [| let x' = $(lift x) in [| $(lift [| x' |]) |]
> >
> > We need to think a bit how to `lift` something of type `Q Exp` because
> > of the `Q` monad. Lifting an `Exp` seems trivial as it's a normal ADT
> > (I tested and this works after deriving 40 instances).
> >
> > You can define `lift2` which lifts an expression twice as follows.
> >
> > ```
> > lift2 :: Lift a => a -> Q Exp
> > lift2 a = lift a >>= \e -> [| return $ $(lift e) |]
> > ```
> >
> > 3. x is defined at stage 1 and used in stage 2
> >
> > foo = [| \x -> [| x |] |] ===>
> >  foo = [| \x -> [| $(lift x) |] |]
> >
> > Desugared with a single call to `lift` like normal.
> >
> > 4. x is defined in stage 2 and used in stage 1
> >
> > foo = [| [| \x -> $(x) |] |]
> >
> > Rejected just like usual. `x` won't be bound when the splice is run.
> >
> > It seems that with some suitable care that things will work out when
> > lifting across multiple levels but that is the point where care needs
> > to be taken.
> >
> > Matt
> >
> >
> >
> > On Thu, Jan 24, 2019 at 5:46 PM Richard Eisenberg <[hidden email]> wrote:
> >>
> >> I think Geoff was primarily concerned with typed Template Haskell, not the untyped variety.
> >>
> >> I, too, have wondered if there was a technical reason behind this restriction, or if merely it was assumed that nested brackets were not worthwhile.
> >>
> >> One question: how would staging work between nesting levels of brackets?
> >>
> >> Richard
> >>
> >>> On Jan 24, 2019, at 12:42 PM, Ben Gamari <[hidden email]> wrote:
> >>>
> >>> Matthew Pickering <[hidden email]> writes:
> >>>
> >>>> There is a check in `RnSplice` which errors on the following program
> >>>> with nested brackets.
> >>>>
> >>> It might be good to explicitly include Geoff Mainland in this thread.
> >>> I'm not sure he'll see it otherwise.
> >>>
> >>> Cheers,
> >>>
> >>> - Ben
> >>>
> >>> _______________________________________________
> >>> ghc-devs mailing list
> >>> [hidden email]
> >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
> >>
>
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
Reply | Threaded
Open this post in threaded view
|

Re: Why are nested brackets disallowed?

Matthew Pickering
In reply to this post by Matthew Pickering
I put up a patch which removes this restriction (for untyped expressions).

https://gitlab.haskell.org/ghc/ghc/merge_requests/259

On Thu, Jan 24, 2019 at 11:46 AM Matthew Pickering
<[hidden email]> wrote:

>
> There is a check in `RnSplice` which errors on the following program
> with nested brackets.
>
> ```
> prog = [| [| True |] |]
>
> T.hs:4:11: error:
>     • Template Haskell brackets cannot be nested (without intervening splices)
>     • In the Template Haskell quotation [| True |]
>       In the Template Haskell quotation [| [| True |] |]
>   |
> 4 | prog = [| [| True |] |]
>   |           ^^^^^^^^^^
>
> ```
>
> As far as I can see the check was added in 2013 in this commit,
> https://github.com/ghc/ghc/commit/d0d47ba76f8f0501cf3c4966bc83966ab38cac27#diff-58794f81a415f148d011de563988c2b5R170
>
> But there is no note, no tests and no comment about why it was added.
>
> I removed the check and added a `BracketE` constructor to the
> template-haskell AST and the
> code compiles fine.
>
> I can also construct a program which needs to be spliced twice and
> this also works fine.
>
> ```
> func Add = [| (+) |]
> func Mul = [| (*) |]
>
> f1 "+" = [| Add |]
> f1 "*" = [| Mul |]
>
> comb s = [| func $(f1 s) |]
> ```
> ```
> res = $($(comb "*"))
> ```
>
> So it seems the restriction is quite arbitrary but I was wondering if
> I was missing some limitation which meant this check was added. I
> would not be surprised if something more complicated goes wrong with
> splicing.
>
> Cheers,
>
> Matt
_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs