<p dir="ltr">In my experience, it is usually a more pragmatic solution to pick the string type that is most suitable for the library's purposes, and leave conversions to the consumer.</p>
<p dir="ltr">In practice, the choice is typically between strict and lazy Text only: bytestrings do not represent strings but byte arrays, so they are not suitable for textual data; and String has atrocious performance, unless the use case is just linear character-wise traversal (and even then, lazy Texts are probably still a better choice). I would only choose String if my library were closely related to another library that has already picked String, and converting to and from Text would introduce a lot of overhead.</p>
<p dir="ltr">The downside of making your API polymorphic is that you will often find yourself having to type-annotate to disambiguate (foo . (bar :: Int -> Text) $ n), or introduce type-binding dummy functions (foo . asText . bar $ n). Another downside is that there is no canonical "StringLike" typeclass, so you either have to write your own, or pick one as a dependency. That said, there are a few libraries out there that aim to make the Haskell string situation less painful, including my own string-convert. They all differ in a few details, it mostly comes down to preference.</p>
<div class="gmail_quote">On Jul 14, 2016 3:00 AM, "Edward Z. Yang" <<a href="mailto:ezyang@mit.edu">ezyang@mit.edu</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello KwangYul,<br>
<br>
Supporting this sort of parametricity is one of the goals of the<br>
Backpack project.  You can see some code that demonstrates<br>
how this might be done: <a href="https://github.com/yihuang/tagstream-conduit/pull/18" rel="noreferrer" target="_blank">https://github.com/yihuang/tagstream-conduit/pull/18</a><br>
Maybe you'll get to use this feature in GHC 8.2!<br>
<br>
A big problem with StringLike type classes is that you must<br>
pre-commit to the set of operations which are supported before<br>
hand. For strings, there are many, many such operations, and it is<br>
difficult to agree a priori what these operations should be.<br>
<br>
Edward<br>
<br>
Excerpts from KwangYul Seo's message of 2016-07-13 17:40:13 -0700:<br>
> Hi all,<br>
><br>
> There are multiple string types in Haskell – String, lazy/strict<br>
> ByteString, lazy/strict Text to name a few. So to make a string handling<br>
> function maximally reusable, it needs to support multiple string types.<br>
><br>
> One approach used by TagSoup library is to make a type class StringLike<br>
> which represents the polymorphic string type and uses it where a String<br>
> type is normally needed. For example,<br>
><br>
> parseTags :: StringLike str => str -> [Tag str]<br>
><br>
> Here parseTags takes a StringLike type instead of a fixed string type.<br>
> Users of TagSoup can pick any of String, lazy/strict ByteString,<br>
> lazy/strict Text because they are all instances of StringLike type class.<br>
><br>
> It seems StringLike type class is quite generic but it is used only in the<br>
> TagSoup package. This makes me wonder what is the idiomatic way to support<br>
> multiple string types in Haskell. What other approaches do we have?<br>
><br>
> Thanks,<br>
> Kwang Yul Seo<br>
_______________________________________________<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-bin/mailman/listinfo/haskell-cafe</a><br>
Only members subscribed via the mailman list are allowed to post.</blockquote></div>