Ticket #1476 (new bug)

Opened 6 years ago

Last modified 4 months ago

Template Haskell: splicing types and patterns

Reported by: igloo Owned by:
Priority: low Milestone: _|_
Component: Template Haskell Version: 6.6.1
Keywords: Cc: alfonso.acosta@…, pho@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Difficulty: Unknown
Test Case: Blocked By:
Blocking: Related Tickets:

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

  Changed 5 years ago by fons

  • cc alfonso.acosta@… added

follow-up: ↓ 3   Changed 5 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

in reply to: ↑ 2   Changed 5 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.

  Changed 5 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

  Changed 5 years ago by igloo

See also #2221.

  Changed 5 years ago by simonpj

  • priority changed from normal to low
  • milestone changed from 6.10 branch to _|_

  Changed 5 years ago by simonmar

  • architecture changed from Unknown to Unknown/Multiple

  Changed 5 years ago by simonmar

  • os changed from Unknown to Unknown/Multiple

  Changed 18 months ago by PHO

  • cc pho@… added
  • failure set to None/Unknown

  Changed 4 months ago by morabbin

Bump; any progress on full TH splices in patterns?

Note: See TracTickets for help on using tickets.