<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>