<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0cm;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:blue;
text-decoration:underline;}
code
{mso-style-priority:99;
font-family:"Courier New";}
pre
{mso-style-priority:99;
mso-style-link:"HTML Preformatted Char";
margin:0cm;
font-size:10.0pt;
font-family:"Courier New";}
span.EmailStyle19
{mso-style-type:personal-reply;
font-family:"Calibri",sans-serif;
color:windowtext;}
span.HTMLPreformattedChar
{mso-style-name:"HTML Preformatted Char";
mso-style-priority:99;
mso-style-link:"HTML Preformatted";
font-family:"Courier New";
mso-fareast-language:EN-GB;}
p.first, li.first, div.first
{mso-style-name:first;
mso-margin-top-alt:auto;
margin-right:0cm;
mso-margin-bottom-alt:auto;
margin-left:0cm;
font-size:11.0pt;
font-family:"Calibri",sans-serif;}
span.highlighted
{mso-style-name:highlighted;}
span.p
{mso-style-name:p;}
span.kt
{mso-style-name:kt;}
span.ow
{mso-style-name:ow;}
span.n
{mso-style-name:n;}
span.o
{mso-style-name:o;}
span.pre
{mso-style-name:pre;}
.MsoChpDefault
{mso-style-type:export-only;
font-family:"Calibri",sans-serif;
mso-fareast-language:EN-US;}
.MsoPapDefault
{mso-style-type:export-only;
margin-top:6.0pt;
margin-right:0cm;
margin-bottom:6.0pt;
margin-left:0cm;}
@page WordSection1
{size:612.0pt 792.0pt;
margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-GB" link="blue" vlink="purple" style="word-wrap:break-word">
<div class="WordSection1">
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-family:"Arial",sans-serif">Perhaps I'm just stupid, and should be disqualified from using such features.<o:p></o:p></span></p>
<p class="MsoNormal" style="margin-left:36.0pt"><span style="font-family:"Arial",sans-serif">Only as a result of this thread (not from the User Guide nor from the paper) do I discover "use" means match-on.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family:"Arial",sans-serif"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-family:"Arial",sans-serif">You are not stupid. And since you misunderstood despite effort, the presentation is – by definition – not as good as it should be.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family:"Arial",sans-serif"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-family:"Arial",sans-serif">The paper focuses pretty much entirely on matching, and takes building for granted. But I can now see that it is not explicit on this point, and that leaves it open to misinterpretation. I
think the paper is reasonably careful to say “match on” rather than “use”, but I wouldn’t bet on it.<o:p></o:p></span></p>
<p class="MsoNormal"><span style="font-family:"Arial",sans-serif"><o:p> </o:p></span></p>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:36.0pt">
<span style="font-family:"Arial",sans-serif">I suggest the User Guide needs an example where a constraint needed for matching (presumably via a View pattern) is not amongst the constraints carried inside the data constructor, nor amongst those needed for building.
Then the limitations in the current design would be more apparent for users.</span><o:p></o:p></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US">The <a href="https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/pattern_synonyms.html?highlight=pattern%20syn#typing-of-pattern-synonyms">
user manual</a> does already speak about the type of a builder, here:<o:p></o:p></span></p>
<p class="first" style="margin-left:36.0pt"><span style="font-family:Symbol">·</span> For a bidirectional
<span class="highlighted">pattern</span> <span class="highlighted">syn</span>onym, a use of the pattern synonym as an expression has the type<o:p></o:p></p>
<pre style="margin-left:36.0pt"><span class="p">(</span><span class="kt">CReq</span><span class="p">,</span> <span class="kt">CProv</span><span class="p">)</span> <span class="ow">=></span> <span class="n">t1</span> <span class="ow">-></span> <span class="n">t2</span> <span class="ow">-></span> <span class="o">...</span> <span class="ow">-></span> <span class="n">tN</span> <span class="ow">-></span> <span class="n">t</span><o:p></o:p></pre>
<p style="margin-left:36.0pt">So in the previous example, when used in an expression,
<span class="pre"><span style="font-size:10.0pt;font-family:"Courier New"">ExNumPat</span></span> has type<o:p></o:p></p>
<pre style="margin-left:36.0pt"><span class="kt">ExNumPat</span> <span class="ow">::</span> <span class="p">(</span><span class="kt">Num</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Eq</span> <span class="n">a</span><span class="p">,</span> <span class="kt">Show</span> <span class="n">b</span><span class="p">)</span> <span class="ow">=></span> <span class="n">b</span> <span class="ow">-></span> <span class="kt">T</span> <span class="n">t</span><o:p></o:p></pre>
<p style="margin-left:36.0pt">Notice that this is a tiny bit more restrictive than the expression
<span class="pre"><span style="font-size:10.0pt;font-family:"Courier New"">MkT</span></span><code><span style="font-size:10.0pt">
</span></code><span class="pre"><span style="font-size:10.0pt;font-family:"Courier New"">42</span></span><code><span style="font-size:10.0pt">
</span></code><span class="pre"><span style="font-size:10.0pt;font-family:"Courier New"">x</span></span> which would not require
<span class="pre"><span style="font-size:10.0pt;font-family:"Courier New"">(Eq</span></span><code><span style="font-size:10.0pt">
</span></code><span class="pre"><span style="font-size:10.0pt;font-family:"Courier New"">a)</span></span>.<o:p></o:p></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US">That does seem to directly address the use of a pattern synonym in an expression, and means that both CReq and Cprov are required at use sites in expressions. It even includes an example of the
sort you wanted. How could we make that clearer?<o:p></o:p></span></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US">Thanks<o:p></o:p></span></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US">Simon<o:p></o:p></span></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span style="font-size:8.0pt">PS: I am leaving Microsoft at the end of November 2021, at which point
<a href="mailto:simonpj@microsoft.com"><span style="color:#0563C1">simonpj@microsoft.com</span></a> will cease to work. Use
<a href="mailto:simon.peytonjones@gmail.com"><span style="color:#0563C1">simon.peytonjones@gmail.com</span></a> instead. (For now, it just forwards to simonpj@microsoft.com.)<o:p></o:p></span></p>
<p class="MsoNormal"><span style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<div style="border:none;border-left:solid blue 1.5pt;padding:0cm 0cm 0cm 4.0pt">
<div>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0cm 0cm 0cm">
<p class="MsoNormal"><b><span lang="EN-US">From:</span></b><span lang="EN-US"> Glasgow-haskell-users <glasgow-haskell-users-bounces@haskell.org>
<b>On Behalf Of </b>Anthony Clayden<br>
<b>Sent:</b> 06 October 2021 06:25<br>
<b>To:</b> Gergõ Érdi <gergo@erdi.hu><br>
<b>Cc:</b> GHC users <glasgow-haskell-users@haskell.org><br>
<b>Subject:</b> Re: Pattern synonym constraints :: Ord a => () => ...<o:p></o:p></span></p>
</div>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<span style="font-family:"Arial",sans-serif">Thanks Gergö, I've read that paper many times (and the User Guide). Nowhere does it make the distinction between required-for-building vs required-for-matching. And since most of the syntax for PatSyns (the `where`
equations) is taken up with building, I'd taken it that "required" means required-for-building.</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<span style="font-family:"Arial",sans-serif">There is one paragraph towards the end of section 6 that kinda hints at the issue here. It's so cryptic it's no help. "An alternative would be to carry two types for each pattern synonym: ...". But already PatSyns
carry two sets of _constraints_. The matrix type after the constraints is determined by the mapping to/from the data constructor. Why would there be two of those? What this paragraph might mean (?) is 'carry three sets of constraints', but put one set in a
completely different signature. As per the proposal.</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<span style="font-family:"Arial",sans-serif">> they [Required constraints] are "required" to be able to use the pattern synonym.</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<span style="font-family:"Arial",sans-serif">Is highly misleading. Only as a result of this thread (not from the User Guide nor from the paper) do I discover "use" means match-on. The paper really does not address typing for "use" for building. I agree with
SPJ's comment (quoted in the proposal) "<span style="color:#24292F">This turns out to be wrong in both directions.</span>"</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<span style="font-family:"Arial",sans-serif">I suggest the User Guide needs an example where a constraint needed for matching (presumably via a View pattern) is not amongst the constraints carried inside the data constructor, nor amongst those needed for building.
Then the limitations in the current design would be more apparent for users.</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<o:p> </o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<span style="font-family:"Arial",sans-serif">Perhaps I'm just stupid, and should be disqualified from using such features. (I keep away from GADTs for those reasons.) So I'm not going to volunteer to revise the User Guide further.</span><o:p></o:p></p>
</div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<o:p> </o:p></p>
</div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
<o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
On Wed, 6 Oct 2021 at 15:26, Gergõ Érdi <<a href="mailto:gergo@erdi.hu">gergo@erdi.hu</a>> wrote:<o:p></o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-right:0cm">
<p class="MsoNormal" style="mso-margin-top-alt:6.0pt;margin-right:0cm;margin-bottom:6.0pt;margin-left:0cm">
If you haven't yet, it is probably a good idea to read section 6 of<br>
<a href="https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgergo.erdi.hu%2Fpapers%2Fpatsyns%2F2016-hs-patsyns-ext.pdf&data=04%7C01%7Csimonpj%40microsoft.com%7Cf208f3e0240646a9829f08d98889d751%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637690948080937568%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C2000&sdata=YhqSQ%2BWSfz5Ycmt8aynh9jJaUVNiiK3kkPrLj1pILx4%3D&reserved=0" target="_blank">https://gergo.erdi.hu/papers/patsyns/2016-hs-patsyns-ext.pdf</a><br>
<br>
On Wed, Oct 6, 2021 at 10:23 AM Gergõ Érdi <<a href="mailto:gergo@erdi.hu" target="_blank">gergo@erdi.hu</a>> wrote:<br>
><br>
> > I'm afraid none of this is apparent from the User Guide -- and I even contributed some material to the Guide, without ever understanding that. Before this thread, I took it that 'Required' means for building -- as in for smart constructors.<br>
><br>
> No, that's not what the required/provided distinction means at all!<br>
><br>
> You should think of both Provided and Required in the context of<br>
> matching, not in the context of building. To be able to use a pattern<br>
> synonym to match on a scrutinee of type T, not only does T have to<br>
> match the scrutinee type of the pattern synonym, but you also must<br>
> satisfy the constraints of the Required constraints -- they are<br>
> "required" to be able to use the pattern synonym. On the flipside,<br>
> once you do use the pattern synonym, on the right-hand side of your<br>
> matched clause you now get to assume the Provided constraints -- in<br>
> other words, those constraints are "provided" to you by the pattern<br>
> synonym.<br>
><br>
> It is true that the builder could have entirely unrelated constraints<br>
> to either (as in the proposal). The current implementation basically<br>
> assumes that the Provided constraints can be provided because the<br>
> builder put them in.<br>
><br>
> Does this make it clearer?<br>
><br>
> On Wed, Oct 6, 2021 at 10:13 AM Anthony Clayden<br>
> <<a href="mailto:anthony.d.clayden@gmail.com" target="_blank">anthony.d.clayden@gmail.com</a>> wrote:<br>
> ><br>
> ><br>
> > Thank you. Yes that proposal seems in 'the same ball park'. As Richard's already noted, a H98 data constructor can't _Provide_ any constraints, because it has no dictionaries wrapped up inside. But I'm not asking it to!<br>
> ><br>
> > The current PatSyn signatures don't distinguish between Required-for-building vs Required-for-matching (i.e. deconstructing/reformatting to the PatSyn). This seems no better than 'stupid theta': I'm not asking for any reformatting to pattern-match, just
give me the darn components, they are what they are where they are.<br>
> ><br>
> > I'm afraid none of this is apparent from the User Guide -- and I even contributed some material to the Guide, without ever understanding that. Before this thread, I took it that 'Required' means for building -- as in for smart constructors. So PatSyns aren't
really aimed to be for smart constructors? I should take that material out of the User Guide?<br>
> ><br>
> ><br>
> > AntC<br>
> ><br>
> ><br>
> > On Wed, 6 Oct 2021 at 10:53, Richard Eisenberg <<a href="mailto:lists@richarde.dev" target="_blank">lists@richarde.dev</a>> wrote:<br>
> >><br>
> >> You're right -- my apologies. Here is the accepted proposal: <a href="https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fghc-proposals%2Fghc-proposals%2Fblob%2Fmaster%2Fproposals%2F0042-bidir-constr-sigs.rst&data=04%7C01%7Csimonpj%40microsoft.com%7Cf208f3e0240646a9829f08d98889d751%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637690948080947564%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C2000&sdata=Cdf7aEeHc8yXFJCn8aX9WdGGJueQsqGK0zY7Ib%2B6FsY%3D&reserved=0" target="_blank">
https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0042-bidir-constr-sigs.rst</a><br>
> >><br>
> >> Richard<br>
> >><br>
> >> On Oct 5, 2021, at 12:38 PM, David Feuer <<a href="mailto:david.feuer@gmail.com" target="_blank">david.feuer@gmail.com</a>> wrote:<br>
> >><br>
> >> To be clear, the proposal to allow different constraints was accepted, but integrating it into the current, incredibly complex, code was well beyond the limited abilities of the one person who made an attempt. Totally severing pattern synonyms from constructor
synonyms (giving them separate namespaces) would be a much simpler design.<br>
> >><br>
> >> On Tue, Oct 5, 2021, 12:33 PM Richard Eisenberg <<a href="mailto:lists@richarde.dev" target="_blank">lists@richarde.dev</a>> wrote:<br>
> >>><br>
> >>><br>
> >>><br>
> >>> 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:<br>
> >>><br>
> >>> > pattern SmartConstr :: Ord a => () => ...<br>
> >>><br>
> >>> Seems to mean:<br>
> >>><br>
> >>> * Required constraint is Ord a -- fine, for building<br>
> >>><br>
> >>><br>
> >>> Yes.<br>
> >>><br>
> >>> * Provided constraint is Ord a -- why? for matching/consuming<br>
> >>><br>
> >>><br>
> >>> No. Your signature specified that there are no provided constraints: that's your ().<br>
> >>><br>
> >>><br>
> >>> 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.<br>
> >>><br>
> >>><br>
> >>> I believe there is no way to have provided constraints in Haskell98. You would need either GADTs or higher-rank types.<br>
> >>><br>
> >>><br>
> >>> This feels a lot like one of the things that's wrong with 'stupid theta' datatype contexts.<br>
> >>><br>
> >>><br>
> >>> 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.<br>
> >>><br>
> >>> For example:<br>
> >>><br>
> >>> checkLT5AndReturn :: (Ord a, Num a) => a -> (Bool, a)<br>
> >>> checkLT5AndReturn x = (x < 5, x)<br>
> >>><br>
> >>> pattern LessThan5 :: (Ord a, Num a) => a -> a<br>
> >>> pattern LessThan5 x <- ( checkLT5AndReturn -> (True, x) )<br>
> >>><br>
> >>><br>
> >>> 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.<br>
> >>><br>
> >>><br>
> >>> For definiteness, the use case is a underlying non-GADT constructor for a BST<br>
> >>><br>
> >>> > Node :: Tree a -> a -> Tree a -> Tree a<br>
> >>> ><br>
> >>> > pattern SmartNode :: Ord a => () => Tree a -> a -> Tree a -> Tree a<br>
> >>><br>
> >>> 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.<br>
> >>><br>
> >>><br>
> >>> 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).<br>
> >>><br>
> >>> 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.<br>
> >>><br>
> >>> Does this help?<br>
> >>><br>
> >>> Richard<br>
> >>> _______________________________________________<br>
> >>> Glasgow-haskell-users mailing list<br>
> >>> <a href="mailto:Glasgow-haskell-users@haskell.org" target="_blank">Glasgow-haskell-users@haskell.org</a><br>
> >>> <a href="https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmail.haskell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fglasgow-haskell-users&data=04%7C01%7Csimonpj%40microsoft.com%7Cf208f3e0240646a9829f08d98889d751%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637690948080957559%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C2000&sdata=z1wP8QMlfRhfNmbX0n0HuoYx6MufLQdMjCTgBVZMqcs%3D&reserved=0" target="_blank">
http://mail.haskell.org/cgi-bin/mailman/listinfo/glasgow-haskell-users</a><br>
> >><br>
> >><br>
> > _______________________________________________<br>
> > Glasgow-haskell-users mailing list<br>
> > <a href="mailto:Glasgow-haskell-users@haskell.org" target="_blank">Glasgow-haskell-users@haskell.org</a><br>
> > <a href="https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmail.haskell.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fglasgow-haskell-users&data=04%7C01%7Csimonpj%40microsoft.com%7Cf208f3e0240646a9829f08d98889d751%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637690948080967559%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C2000&sdata=dw%2BRrhD1RqrZYMSCjXNRofuuC6PHtgRjVd%2BmlBQQkoI%3D&reserved=0" target="_blank">
http://mail.haskell.org/cgi-bin/mailman/listinfo/glasgow-haskell-users</a><o:p></o:p></p>
</blockquote>
</div>
</div>
</div>
</div>
</body>
</html>