<div dir="ltr"><div dir="ltr"><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">Thank you Richard (and for the reply to a similar topic on the cafe).</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">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:</font></div><div><font face="arial, sans-serif"><a href="http://web.archive.org/web/20151208175102/http://code.haskell.org/~dons/haskell-1990-2000/threads.html#04062">http://web.archive.org/web/20151208175102/http://code.haskell.org/~dons/haskell-1990-2000/threads.html#04062</a><br></font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">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.</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">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:</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">> <span style="color:rgb(0,0,0);font-size:1em">*pattern-matching* on MkT as *eliminating* a constraint. </span><span style="color:rgb(0,0,0);font-size:1em">But since the dictionary isn't stored in the constructor we can't </span><span style="color:rgb(0,0,0);font-size:1em">eliminate it.</span></font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">So at first sight, I was hoping that a PatternSyn</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">>    pattern SmartConstr :: Ord a => () => blah</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">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.</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">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:</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">>    pattern SmartConstr :: Ord a => Ord a => blah</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">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.</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">You say "the design was too complicated". And yet SPJ on that thread says "<span style="color:rgb(0,0,0);font-size:1em">This is the simpler choice".</span></font></div><div><span style="color:rgb(0,0,0);font-size:1em"><font face="arial, sans-serif"><br></font></span></div><div><font face="arial, sans-serif"><span style="color:rgb(0,0,0);font-size:1em">> </span> you want a separate smartNode function (not a pattern synonym)</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">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?</font></div><div><span style="color:rgb(0,0,0);font-size:1em"><font face="arial, sans-serif"><br></font></span></div><div><span style="color:rgb(0,0,0);font-size:1em"><font face="arial, sans-serif">AntC</font></span></div><font face="arial, sans-serif"><br></font><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 6 Oct 2021 at 05:32, Richard Eisenberg <<a href="mailto:lists@richarde.dev">lists@richarde.dev</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><br><div><br><blockquote type="cite"><div>On Oct 3, 2021, at 5:38 AM, Anthony Clayden <<a href="mailto:anthony.d.clayden@gmail.com" target="_blank">anthony.d.clayden@gmail.com</a>> wrote:</div><div><div dir="ltr"><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">>    pattern  SmartConstr :: Ord a => () => ...</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">Seems to mean:</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">* Required constraint is Ord a  -- fine, for building</font></div></div></div></blockquote><div><br></div><div>Yes.</div><br><blockquote type="cite"><div><div dir="ltr"><div><font face="arial, sans-serif">* Provided constraint is Ord a  -- why? for matching/consuming</font></div></div></div></blockquote><div><br></div><div>No. Your signature specified that there are no provided constraints: that's your ().</div><br><blockquote type="cite"><div><div dir="ltr"><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">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.</font></div></div></div></blockquote><div><br></div><div>I believe there is no way to have provided constraints in Haskell98. You would need either GADTs or higher-rank types.</div><br><blockquote type="cite"><div dir="ltr"><div><br></div><div><font face="arial, sans-serif">This feels a lot like one of the things that's wrong with 'stupid theta' datatype contexts.</font></div></div></blockquote><div><br></div><div>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.</div><div><br></div><div>For example:</div><div><br></div><div></div><blockquote type="cite"><div>checkLT5AndReturn :: (Ord a, Num a) => a -> (Bool, a)</div><div>checkLT5AndReturn x = (x < 5, x)</div><div><br></div><div>pattern LessThan5 :: (Ord a, Num a) => a -> a</div><div>pattern LessThan5 x <- ( checkLT5AndReturn -> (True, x) )</div></blockquote><div><br></div><div>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.</div><br><blockquote type="cite"><div dir="ltr"><div><br></div><div><font face="arial, sans-serif">For definiteness, the use case is a underlying non-GADT constructor for a BST</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">>      Node :: Tree a -> a -> Tree a -> Tree a</font></div><div><font face="arial, sans-serif">></font></div><div><font face="arial, sans-serif">>    pattern SmartNode :: Ord a => () => Tree a -> a -> Tree a -> Tree a</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">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.</font></div></div></blockquote><div><br></div><div>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).</div><div><br></div><div>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.</div><div><br></div><div>Does this help?</div><div><br></div><div>Richard</div></div></div></blockquote></div></div>