<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Mon, May 4, 2015 at 11:37 AM, Reid Barton <span dir="ltr"><<a href="mailto:rwbarton@gmail.com" target="_blank">rwbarton@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><span class="">On Mon, May 4, 2015 at 12:58 PM, David Feuer <span dir="ltr"><<a href="mailto:david.feuer@gmail.com" target="_blank">david.feuer@gmail.com</a>></span> wrote:<br></span><div class="gmail_extra"><div class="gmail_quote"><span class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><p dir="ltr">Wouldn't your concerns about NonEmpty be addressed by keeping its type abstract? Then something like Liquid Haskell could be used to define it better.<br></p></blockquote></span><div>There are (at least) two possible designs for a "non-empty list type".<br><br></div><div>1. A refinement type (as in LiquidHaskell) of [t] whose values include only the non-empty lists. Call it NonEmptyLiquid t. You can pass a NonEmptyLiquid t to a function that expects a [t], and you can pass a [t] to a function that expects a NonEmptyLiquid [t] if the compiler can prove that your [t] is nonempty. If it can't then you can add a runtime test for emptiness and in the non-empty case, the compiler will know the list is non-empty.<br><br></div><div>2. A new type NonEmptySolid t that is totally unrelated to [t] like you can define in Haskell today. The advantage is that NonEmptySolid is a full-fledged type constructor that can have instances, be passed to other type constructors and so on. The disadvantage is that you need to explicitly convert in your program (and possibly do a runtime conversion also) in either direction between [t] and NonEmptySolid t.<br><br></div><div>I think most people who want a "non-empty list type" want 1, not 2. Option 2 is bad for API design because it forces the users of your library to care exactly as much as you do about non-emptiness. If you imagine adding other sorts of lists like infinite lists, fixed-length or bounded-length lists, lists of even length etc. then it quickly becomes clear that having such an array of incompatible list types is not the way to go. We just want lists to be lists, but we also want the compiler to make sure we don't try to take the head of an empty list.<br></div></div></div></div></blockquote><div><br></div><div>I don't think it is bad API design to have the data types explain the properties of the input. Quite the opposite. In the case of head/tail the user *must* care the same about emptiness as the library: that difference makes it common place to ban usage of those functions.</div><div><br></div><div>I agree with Henning that I don't suffer from awkwardness with using NonEmpty: I just use `toList` on occasion.</div><div><br></div><div>The issue you have not raised that I am more concerned with is that NonEmpty only works for lists.</div><div>Michael and I figured out how to extend the concept to any (Mono)Foldable structure and also to be able to demand lengths of > 1.</div><div>I still found that directly using NonEmpty is useful just as directly using a Haskell list is still useful.</div><div><br></div><div><a href="https://github.com/snoyberg/mono-traversable#minlen">https://github.com/snoyberg/mono-traversable#minlen</a><br></div><div><a href="http://hackage.haskell.org/package/mono-traversable-0.9.1/docs/Data-MinLen.html">http://hackage.haskell.org/package/mono-traversable-0.9.1/docs/Data-MinLen.html</a><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>Those who use a NonEmpty type prefer option 2 over option 0 "type NonEmptyGas t = [t] -- and just hope"; but that doesn't mean they prefer option 2 over option 1. Those who really want option 2 can also define it as a newtype wrapper on option 1, as you noted.<br><br></div><div>So, to answer your question, no, it wouldn't really make a difference if the NonEmpty type was abstract. That would just smooth the transition to a design that I think people don't really want.<br><br></div><div>Finally, let me reiterate that there seem to be no advantages to moving a NonEmpty type into base rather than into its own small package. We don't need base to swallow up every small popular package.<br></div></div></div></div></blockquote><div><br></div><div>I agree that this point should be debated more. That should happen separately from the refinement vs. NonEmpty debate. If it is a separate package then there is no debate about refinements to have anyways.</div><div><br></div><div>I think it would be good to require a justification for putting anything into base.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>Regards,<br></div><div>Reid Barton<br></div></div></div></div>
<br>_______________________________________________<br>
Libraries mailing list<br>
<a href="mailto:Libraries@haskell.org">Libraries@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/libraries</a><br>
<br></blockquote></div><br></div></div>