Pattern synonym constraints :: Ord a => () => ...

Anthony Clayden anthony.d.clayden at gmail.com
Wed Oct 6 00:55:48 UTC 2021


Thank you Richard (and for the reply to a similar topic on the cafe).

What I meant by the comparison to 'stupid theta' is that GHC's
implementation of datatype contexts used to be mildly useful and moderately
sensible. Then it went stupid, following this 'Contexts on datatype
declarations' thread:
http://web.archive.org/web/20151208175102/http://code.haskell.org/~dons/haskell-1990-2000/threads.html#04062

With the benefit of a great deal of hindsight, and noting that
PatternSynonyms makes explicit there's a builder vs a matcher, I'd say SPJ
was right and Wadler was wrong.

In particular consider trying to implement a Foldable instance (or for any
constructor class): the instance head doesn't reveal the 'content type'
`a`, so there's no way to provide `Ord a`. _But we don't need_ `Ord a`,
because the fold is consuming the content, not building a Foldable
structure. As SPJ says:

> *pattern-matching* on MkT as *eliminating* a constraint. But since the
dictionary isn't stored in the constructor we can't eliminate it.

So at first sight, I was hoping that a PatternSyn

>    pattern SmartConstr :: Ord a => () => blah

would give the pre-May 1999 GHC behaviour for matching -- that is, Provide
nothing, and therefore ask for nothing if the constructor/PatSyn appears
only in a matcher position.

I'm afraid that I don't get your answer wrt PatternSyns that wrap H98
datatypes: how do I demonstrate a difference between the above sig vs:

>    pattern SmartConstr :: Ord a => Ord a => blah

It seems to me the shorthand form (with a single `=>`) should be equiv to
the latter, allowing the former nothing-Provided `Ord a => () => blah` to
mean something different.

You say "the design was too complicated". And yet SPJ on that thread says "This
is the simpler choice".

>  you want a separate smartNode function (not a pattern synonym)

I might as well have a SmartNode PatSyn and (unidirectional)
MatcherOnlyNode PatSyn -- which was my work-round in the O.P. Can't you see
that's dysergonomic?

AntC

On Wed, 6 Oct 2021 at 05:32, Richard Eisenberg <lists at richarde.dev> wrote:

>
>
> On Oct 3, 2021, at 5:38 AM, Anthony Clayden <anthony.d.clayden at gmail.com>
> wrote:
>
> >    pattern  SmartConstr :: Ord a => () => ...
>
> Seems to mean:
>
> * Required constraint is Ord a  -- fine, for building
>
>
> Yes.
>
> * Provided constraint is Ord a  -- why? for matching/consuming
>
>
> No. Your signature specified that there are no provided constraints:
> that's your ().
>
>
> I'm using `SmartConstr` with some logic inside it to validate/build a
> well-behaved data structure. But this is an ordinary H98 datatype, not a
> GADT.
>
>
> I believe there is no way to have provided constraints in Haskell98. You
> would need either GADTs or higher-rank types.
>
>
> This feels a lot like one of the things that's wrong with 'stupid theta'
> datatype contexts.
>
>
> You're onto something here. Required constraints are very much like the
> stupid theta datatype contexts. But, unlike the stupid thetas, required
> constraints are sometimes useful: they might be needed in order to, say,
> call a function in a view pattern.
>
> For example:
>
> checkLT5AndReturn :: (Ord a, Num a) => a -> (Bool, a)
> checkLT5AndReturn x = (x < 5, x)
>
> pattern LessThan5 :: (Ord a, Num a) => a -> a
> pattern LessThan5 x <- ( checkLT5AndReturn -> (True, x) )
>
>
> My view pattern requires (Ord a, Num a), and so I must declare these as
> required constraints in the pattern synonym type. Because vanilla data
> constructors never do computation, any required constraints for data
> constructors are always useless.
>
>
> For definiteness, the use case is a underlying non-GADT constructor for a
> BST
>
> >      Node :: Tree a -> a -> Tree a -> Tree a
> >
> >    pattern SmartNode :: Ord a => () => Tree a -> a -> Tree a -> Tree a
>
> with the usual semantics that the left Tree holds elements less than this
> node. Note it's the same `a` with the same `Ord a` 'all the way down' the
> Tree.
>
>
> Does SmartNode need Ord a to match? Or just to produce a node? It seems
> that Ord a is used only for production, not for matching. This suggests
> that you want a separate smartNode function (not a pattern synonym) and to
> have no constraints on the pattern synonym, which can be unidirectional
> (that is, work only as a pattern, not as an expression).
>
> It has been mooted to allow pattern synonyms to have two types: one when
> used as a pattern and a different one when used as an expression. That
> might work for you here: you want SmartNode to have no constraints as a
> pattern, but an Ord a constraint as an expression. At the time, the design
> with two types was considered too complicated and abandoned.
>
> Does this help?
>
> Richard
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/glasgow-haskell-users/attachments/20211006/fe8b5ffe/attachment.html>


More information about the Glasgow-haskell-users mailing list