<div dir="ltr"><div><div><div>How does compiler can infer a type for "allEven = foldMap even" ?<br></div><br></div><div>Something like<br></div>allEven :: (Monoid (aspect Bool), Integral a) => [a] -> Bool ?<br><br></div>Should all Bool's in function body have the same aspects?<br><div><div><div><pre><br></pre></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">2017-05-06 19:42 GMT+03:00 MarLinn <span dir="ltr"><<a href="mailto:monkleyon@gmail.com" target="_blank">monkleyon@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div text="#000000" bgcolor="#FFFFFF">
<p>Hi people,</p>
<p>in the last couple days this list has once again seen examples of
how our class system is not perfect yet. Here are some of the
problems we face:<br>
</p>
<ul>
<li>Useful, but confusing instances like <tt>Foldable ((,) a)</tt></li>
<li>Alternative possible instances like <tt>Alternative []</tt></li>
<li>Orphan instances</li>
<li>Reliance on the order of arguments makes some instances
impossible, for example <tt>Traversable (,a)</tt></li>
</ul>
<p>How we usually resolve some of such issues is with <tt>newtype</tt>.
Among the drawbacks are<br>
</p>
<ul>
<li>This clutters code with artificial wrappers and unwrappers
that have nothing to do with the task at hand<br>
</li>
<li>It implies two levels of hierarchy by marking the one instance
without a <tt>newtype</tt> as special</li>
<li>Every type needs its own wrapper. E.g. a <tt>Foldable (,a)</tt>
(if possible) would need a different wrapper from a <tt>Foldable
(a,,c)</tt></li>
<li>Definitions are scattered at unexpected places, like <tt>All</tt>
and <tt>Any</tt>, partly to avoid orphan instances.<br>
</li>
</ul>
<p>After some thought I therefore propose a language extension I
call "aspects". Keep in mind that this is a very rough draft just
to gauge your reaction.<br>
</p>
<p>The core change would be the introduction of a keyword "<tt>aspect</tt>"
that would work in a comparable way to the keyword "<tt>module</tt>".
In other words you could say<br>
</p>
<pre> aspect Data.Aspect.ChooseNonEmpty where
import qualified Data.Set as Set
instance Alternative [] where
empty = []
a <|> b = if null a then b else a
instance Alternative Set.Set where …
empty = Set.empty
a <|> b = if null a then b else a
</pre>
<p>Changes compared to a normal module would be:<br>
</p>
<ul>
<li>An aspect can only contain instances</li>
<li>An aspect can import anything, but exports only instances</li>
<li>An aspect will never produce orphan instance warnings (duh.)</li>
<li>An aspect can be a file level definition, but it can also be
contained in a module (we'll see why that is useful)</li>
</ul>
<p>You also wouldn't import an aspect like a normal module, but with
a second syntax extension:<br>
</p>
<pre> import Data.List under (Data.Aspect.ChooseNonEmpty)
import qualified Data.Set as Set hiding (Set)
import qualified Data.Set under (Default, Data.Aspect.ChooseNonEmpty) as CNE (Set)</pre>
<p>So you could also import the same structure twice with different
aspects under different names:<br>
</p>
<pre> import Data.Bool
import qualified Data.Bool under (Data.Aspect.All) as All (Bool)
import qualified Data.Bool under (Data.Aspect.Any) as Any (Bool)
</pre>
<p>Now, because of the first import, you could use the boolean
functions normally, and even use the normal <tt>Bool</tt> type in
signatures. And because of the qualified imports if you want to
use one of the <tt>Monoid</tt> instances, all you would have to
do is change <tt>Bool</tt> in the type signature to <tt>Any.Bool</tt>
or <tt>All.Bool</tt> respectively, like so:</p>
<pre> allEven :: (Integral a) => [a] -> Bool
allEven = foldMap even -- error: Could not deduce (Monoid Bool)…
-- old way
allEven :: (Integral a) => [a] -> Bool
allEven = getAll . foldMap (All . even)
-- new way
allEven :: (Integral a) => [a] -> All.Bool -- qualified name adds the monoidal aspect (and possibly others)
allEven = foldMap even -- works
</pre>
<p>In other words, aspects would only be used for instance lookups.
That is also why you could state several aspects at once when
importing. Conflicts would be solved as usual: All is well until
you try to use class functions that create an ambiguity.</p>
<p>I imagine a few special rules to make backwards compatibility
easier. Most importantly, you could define default aspects in
several ways:<br>
</p>
<ul>
<li><tt>aspect Default where …</tt><tt> --</tt>
reserved aspect name</li>
<li><tt>default aspect</tt><tt> </tt><tt>ChooseNonEmpty</tt><tt>
where</tt><tt> …</tt><tt> --</tt> re-used reserved keyword,
but also gives a name to the aspect</li>
<li><tt>default aspect where … --</tt> short form
for <tt>default aspect Default where …</tt></li>
<li>An instance defined in a module outside of an aspect would
automatically be in the <tt>Default</tt> aspect. In other words
the definition can be seen as a short form of a local extension
to the aspect. That's also why aspects would be allowed to be
part of a module.</li>
</ul>
<p>If you don't specify an aspect while importing, it would be
imported under the <tt>Default</tt> aspect. To hide the <tt>Default</tt>
aspect, just don't add it to the aspect list when importing.</p>
<p>Other random thoughts about this:<br>
</p>
<ul>
<li>An aspect doesn't need to be complete. E.g. I imagine an
aspect that only defines <tt>Alternative.empty</tt>, with
several other aspects relying on that by importing this
incomplete aspect. OO programmers might call them abstract
aspects. This might possibly help resolve some disputes about
the "perfect" hierarchy.<br>
</li>
<li>If aspects can be part of a module, can aspects also be part
of an aspect? Maybe, but I haven't made a cost-benefit analysis
yet.</li>
<li>Aspects seem to form a level of container between definitions
and modules. Maybe there should also be a new container type (or
several) for the other parts of code? Say, a container that can
contain everything <i>but</i> instances.</li>
<li>There could be an extension to the export syntax to choose
which aspects to export. I just don't see the usefulness right
now.</li>
<li>There could also be special syntax like <tt>import * under
(Default,SpecialAspect)</tt> as a short form to add some
aspects to every imported module.</li>
<li>The <tt>Default</tt> aspect is obviously extensible. I
consider that a universally useful, if not essential feature. On
the other hand in this proposal aspects use the module name
space – which means such extensions would only be possible on a
package level or by using several code folder roots. I'm not
sure I'm happy with that.<br>
</li>
<li>The proposal doesn't solve the issue that instances rely the
order of arguments. But an introduction of such new syntax might
be a good time to introduce two extensions at once. I imagine
something like <tt>instance Foldable (,) _ a where…</tt></li>
</ul>
<p>The biggest drawbacks from this idea that I can see right now
are:</p>
<ul>
<li>The language extension might be infectious: once one library
in a project uses it, many parts of the project might need it.
This is different from most extensions that stay rather local.</li>
<li>Such a change might necessitate huge amounts of cpp.</li>
<li>Because aspects would be extensible and would have a global
name space, care would have to be taken to not create a mess.<br>
</li>
</ul>
<p>So… feel free to bikeshed and more importantly criticize! What am
I overlooking? Would you consider such an idea worthwhile? Happy
to hear your thoughts.<br>
</p>
<p>Cheers,<br>
MarLinn<br>
</p>
</div>
<br>______________________________<wbr>_________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-<wbr>bin/mailman/listinfo/haskell-<wbr>cafe</a><br>
Only members subscribed via the mailman list are allowed to post.<br></blockquote></div><br></div>