Opened 10 years ago

Closed 3 years ago

#1476 closed bug (fixed)

Template Haskell: splicing types and patterns

Reported by: igloo Owned by:
Priority: low Milestone: 7.10.1
Component: Template Haskell Version: 6.6.1
Keywords: Cc: alfonso.acosta@…, pho@…, ghc.haskell.org@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case: th/T1476 th/T1476b
Blocked By: Blocking:
Related Tickets: Differential Rev(s): Phab:D433
Wiki Page:

Description

In http://www.haskell.org/pipermail/template-haskell/2003-February/000021.html Simon Peyton Jones writes:

We claim to allow you to write splices in (a) types and (b) patterns.
I'm very dubious about (b). Consider]
    x = 4
      
    y :: Patt 
    y = [p| ... |]

    f $y = x

Question: where is x bound?  It looks as though x can be bound by the
spliced-in pattern or by the top-level binding.  You can't tell without
knowing what $y expands to.  We argue in our paper against non-top-level
declaration splices because that would lead to ambiguity of exactly this
sort.

It turns out that it's very inconvenient to implement pattern splices in
GHC, for exactly this reason.  We can't figure out the binding structure
till we expand the splice.  We can't expand the splice till typechecking
time.  But the renamer currently fixes the binding structure before type
checking.    Changing this would be a big upheaval.

Conclusion: pattern splices are hard to implement, and dubious from a
programming point of view.  I propose to drop them, for now at least.


Type splices have some similar echoes.  Consider
      
    y :: Type 
    y = [t| a -> a |]

    f :: $y

What is f polymorphic in?   The trouble concerns Haskell's implicit
quantification.  I guess there are three possibilities:

a) $y expands to "a -> a", and that is implicitly universally quantified
to "forall a. a->a".
b) The implicit quantification happens at the [t| ...|] brackets, so
that $y expands to
    "forall a. a->a"
c) $y expands to "a -> a" with no implicit quantification anywhere.

I'm pretty sure that we should adopt (b).  After all, we want a
lexical-scoping rule for TH, so we have to say where 'a' is bound.

That would still in principle allow
      
    y :: Type
    y = return (Tvar "a" `Arrow` Tvar "a")

Since it's the renamer that does implicit quantification, it'd be quite
awkward to make the implicit quantification at the splice site "see" the
free variables 'a'.

The link with the pattern stuff is this.  If you see
    f :: $y -> b

then what are the implicit for-alls?  My answer: the implicit for-alls
are just for "b", not for any free vars of $y.

Since then, the only solution for pattern splices I recall seeing is

f ${x,z}y = x

which asserts that the splice introduces the set of identifiers {x,z}.

Change History (18)

comment:1 Changed 10 years ago by fons

Cc: alfonso.acosta@… added

comment:2 Changed 10 years ago by simonpj

GHC HEAD now has Geoff Mainland's quasi-quoting patch, which does allow splicing into patterns. (But not types.)

See http://www.haskell.org/ghc/dist/current/docs/users_guide/template-haskell.html#th-quasiquotation

I wonder if that helps?

Simon

comment:3 in reply to:  2 Changed 10 years ago by fons

Replying to simonpj:

GHC HEAD now has Geoff Mainland's quasi-quoting patch, which does allow splicing into patterns. (But not types.)

Cool! I have just read the paper and seems to add a lot of possibilities for embedding DSLs in Haskell.

I wonder if that helps?

Yes, it would certainly help (assuming there is a Haskell quasiquote parser available).

The fact that custom quasiquotes (I don't know if it's an appropiate term to call Mainland's work) are already working with GHC 6.9, makes me think that implementing TH pattern quasiquoting/splicing should be indeed very similar.

In fact, Mainland's quasiquotes could be viewed as syntactic sugar for TH quasiquotes

Using the new quasiquotes one can do something like

expParser :: String -> Q Exp
patParser :: String -> Q Pat


expr = QuasiQuoter expParser patParser


[$exp|randomstring|]

Which would be equivalent to (quasiquoting/splicing was working for patterns for TH).

expParser :: String -> Q Exp
patParser :: String -> Q Pat

$(expParser "randomstring")
$(patParser "randomstring") 

The only major difference I see is that with Mainland's implementation the pattern or expression parser is dynamically chosen depending on its context.

comment:4 Changed 10 years ago by simonpj

No, there's another major difference: a QQ splice is the result of applying a constant function (the parser) to a string. The QQ splice is run in the renamer, before type checking even begins, while scopes are being resolved.

In contrast TH splices run an arbitrary Haskell expression, which must be typechecked first. This is therefore done during type checking. It's much harder to deal with patterns. See the discussion of TH splices that bind variables in http://research.microsoft.com/~simonpj/tmp/notes2.ps.

So they are similar, yes, which is why the documentation appears in the TH section of the manual, but QQ splices have a very particular form (as you describe above).

Bottom line: I don't yet see a good design for full TH splices in patterns.

Simon

comment:5 Changed 9 years ago by igloo

See also #2221.

comment:6 Changed 9 years ago by simonpj

Milestone: 6.10 branch_|_
Priority: normallow

comment:7 Changed 9 years ago by simonmar

Architecture: UnknownUnknown/Multiple

comment:8 Changed 9 years ago by simonmar

Operating System: UnknownUnknown/Multiple

comment:9 Changed 6 years ago by PHO

Cc: pho@… added
Type of failure: None/Unknown

comment:10 Changed 5 years ago by morabbin

Bump; any progress on full TH splices in patterns?

comment:11 Changed 3 years ago by liyang

Cc: ghc.haskell.org@… added

comment:12 Changed 3 years ago by goldfire

Differential Rev(s): Phab:D433
Milestone: 7.10.1
Status: newpatch

Now that splices are run from the renamer, this was relatively easy.

However, the resulting code is far from elegant, and I would love some help in making it better. See the Phab:D433 for more info on the inelegant code.

comment:13 Changed 3 years ago by Richard Eisenberg <eir@…>

comment:14 Changed 3 years ago by Richard Eisenberg <eir@…>

In d627c5cf81fcce05ec160edc5be907297ff05c33/ghc:

Test that nested pattern splices don't scope (#1476).

Test case: th/T1476b.

comment:15 Changed 3 years ago by Richard Eisenberg <eir@…>

In 2346de44330a4309b840e26ddd1ded23f92c6f81/ghc:

Fix #1476 by making splice patterns work.

Unfortunately, splice patterns in brackets still do not work
because we don't run splices in brackets. Without running a pattern
splice, we can't know what variables it binds, so we're stuck.

This is still a substantial improvement, and it may be the best
we can do. Still must document new behavior.

comment:16 Changed 3 years ago by Richard Eisenberg <eir@…>

In 1b22d9f288cbf819be90ec42b254fb1b67dded2d/ghc:

Release notes for #1476, #7484.

comment:17 Changed 3 years ago by Richard Eisenberg <eir@…>

In cfa574cea30b411080de5d641309bdf135ed9be5/ghc:

Update manual for pattern splices (#1476)

comment:18 Changed 3 years ago by goldfire

Resolution: fixed
Status: patchclosed
Test Case: th/T1476 th/T1476b
Note: See TracTickets for help on using tickets.