<div dir="ltr">It happens very often that I want to convert a number of values to strings and<br>concatenate those strings into one. No surprise there, of course. Well, I&#39;d<br>prefer to do it efficiently and with as little code as necessary.<br>
<br><span style="font-family: courier new,monospace;">&gt; {-# LANGUAGE TypeSynonymInstances #-}</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&gt; module ShowsDemo where</span><br style="font-family: courier new,monospace;">
<br>Let&#39;s say I want to generate the string &quot;(42 abc)&quot; starting with a number and a<br>string stored in variables.<br><br><span style="font-family: courier new,monospace;">&gt; n = 42 :: Int</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&gt; s = &quot;abc&quot;</span><br style="font-family: courier new,monospace;"><br>What are my options?<br><br>There&#39;s the obvious approach that&#39;s described in every tutorial, book, and<br>
research paper (for didactic purposes, of course).<br><br><span style="font-family: courier new,monospace;">&gt; ex1 = &quot;(&quot; ++ show n ++ &quot; &quot; ++ s ++ &quot;)&quot;</span><br style="font-family: courier new,monospace;">
<br>It&#39;s pretty concise, but it&#39;s horribly inefficient due to the use of (++).<br><br>Then, there&#39;s the ShowS approach.<br><br><span style="font-family: courier new,monospace;">&gt; ex2 = showChar &#39;(&#39; . shows n . showChar &#39; &#39; . showString s . showChar &#39;)&#39; $ &quot;&quot;</span><br style="font-family: courier new,monospace;">
<br>This is more efficient, but now the code has bloated up a lot.<br><br>Why can&#39;t I have my cake and eat it, too? I want to write with as little code as<br>|ex1| (or less if possible), and I want it to be as efficient as |ex2|.<br>
<br>I propose this example as an improvement.<br><br><span style="font-family: courier new,monospace;">&gt; ex3 = &#39;(&#39; .+. n .+. &#39; &#39; .+. s .$. &#39;)&#39;</span><br style="font-family: courier new,monospace;">
<br>It uses a class I&#39;m calling |Shows|. The class has one method that simply<br>converts a value to the type |ShowS|, where |ShowS| is a type synonym for<br>|String -&gt; String| and is defined in the Prelude.<br><br>
<span style="font-family: courier new,monospace;">&gt; class Shows a where</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&gt;&nbsp;&nbsp; toShows :: a -&gt; ShowS</span><br style="font-family: courier new,monospace;">
<br>Notice the lack of context involving the |Show| class. That&#39;s important, because<br>it allows us to create more instances than we could if we were restricted by<br>|(Show a) =&gt; ...|, esp. the |ShowS| instance below.<br>
<br>The instances for types are all very simple. Most will appear like the instance<br>for |Int|.<br><br><span style="font-family: courier new,monospace;">&gt; instance Shows Int where</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&gt;&nbsp;&nbsp; toShows = shows</span><br style="font-family: courier new,monospace;"><br>Since we don&#39;t have |Show| in the class context above, we can&#39;t make this a<br>default method.<br>
<br>We need a few special instances for |Char| and |String| to make these types<br>convenient to use in the expected way.<br><br><span style="font-family: courier new,monospace;">&gt; instance Shows Char where</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&gt;&nbsp;&nbsp; toShows = showChar</span><br style="font-family: courier new,monospace;"><br><span style="font-family: courier new,monospace;">&gt; instance Shows String where</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&gt;&nbsp;&nbsp; toShows = showString</span><br style="font-family: courier new,monospace;"><br>We also need an instance for |ShowS| in order to facilitate concatenation.<br><br><span style="font-family: courier new,monospace;">&gt; instance Shows ShowS where</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&gt;&nbsp;&nbsp; toShows = id</span><br style="font-family: courier new,monospace;"><br>Now, we define a few operators that use |toShows| and make our lives easier and<br>our code more concise.<br>
<br>The |(.+.)| replaces list appending, |(++)|, in |ex1| and function composition,<br>|.|, in |ex2|.<br><br><span style="font-family: courier new,monospace;">&gt; infixl 5 .+.</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&gt; (.+.) :: (Shows a, Shows b) =&gt; a -&gt; b -&gt; ShowS</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&gt; a .+. b = toShows a . toShows b</span><br style="font-family: courier new,monospace;">
<br>The |(.$.)| replaces the need for |($)| in |ex2|.<br><br><span style="font-family: courier new,monospace;">&gt; infixl 4 .$.</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&gt; (.$.) :: (Shows a, Shows b) =&gt; a -&gt; b -&gt; String</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&gt; a .$. b = (a .+. b) &quot;&quot;</span><br style="font-family: courier new,monospace;"><br>I would find something like this very useful. I&#39;m guessing the idea can be<br>
applied to |ByteString| as well. Does it exist in some other form?<br><br>Sean<br></div>