Typing of Pattern Synonyms: Required vs Provided constraints

Anthony Clayden anthony.d.clayden at gmail.com
Thu Jan 6 02:19:31 UTC 2022


There was an interesting exchange between the authors of Haskell compilers
back in 1999 (i.e. when there were multiple compilers)
http://web.archive.org/web/20151001142647/http://code.haskell.org/~dons/haskell-1990-2000/msg04061.html

I was trying to simulate SPJ's point of view, using PatternSynonyms.

>
>    {-#  LANGUAGE DatatypeContexts, PatternSynonyms  #-}
>
>    data Ord a => TSPJ a = MkTSPJ a a
>
>    pattern PatTSPJ :: (Ord a) => () => a -> a -> TSPJ a    -- empty
Provided
>    pattern PatTSPJ x y = MkTSPJ x y
>
>    unPatTSPJ :: TSPJ a -> (a, a)                            -- no
constraints
>    unPatTSPJ (PatTSPJ x y) = (x, y)
>

`unPatSPJ`'s binding rejected `No instance for (Ord a) arising from a
pattern`. If I don't give a signature, inferred `unPatTSPJ :: Ord b => TSPJ
b -> (b, b)`.

Taking the DatatypeContext off the `data` decl doesn't make a difference.

So Pattern syns seem to be giving exactly the 'stupid theta' behaviour.

The User Guide
https://downloads.haskell.org/~ghc/8.10.7/docs/html/users_guide/glasgow_exts.html#typing-of-pattern-synonyms
says


   -

   ⟨CProv⟩ are the constraints *made available (provided)* by a successful
   pattern match.

But it doesn't mean that. It's more like "⟨CProv⟩ are the constraints made
available *in addition to ⟨CReq⟩* (provided union required) by a successful
pattern match."

Or ... is there some way to simulate the up-to-1999 GHC behaviour? (I
happen to agree with SPJ; Wadler wasn't thinking it through; consider for
example constructor classes over type constructors with constraints:
there's nothing in the instance head for the constraint to attach to. Now
that we have GADTs -- which are appropriate for a different job -- that DT
Contexts perhaps were being (ab-)used for -- I agree more strongly with
SPJ.)

With GADTs I could get a `unGSPJ` that doesn't expose/provide the
constraint, but it does that by packing the constraint/dictionary
(polluting) inside the data constructor. Not  what I want. As SPJ says
down-thread

 "when you take a constructor *apart*, the invariant must hold
	by construction: you couldn't have built the thing you are taking
	apart unless invariant held.  So enforcing the invariant again is
	redundant; and in addition it pollutes the type of selectors."


AntC
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/glasgow-haskell-users/attachments/20220106/24b56d7a/attachment.html>


More information about the Glasgow-haskell-users mailing list