<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> 
<head>
<title>Comparison of Data Values with Limits</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="pandoc" />
<meta name="copyright" content="Copyright &#169; 2008-2011 Péter Diviánszky" />
<link rel="shortcut icon" href="icon.ico" />
<script src="common_en.js" charset="utf-8" type="text/javascript"></script> 
<link rel="stylesheet" href="common.css" type="text/css" />
</head>
<body onload="javascript:resetForms(); javascript:slidy_init();">
<div><h1 class="cover">Comparison of Data Values with Limits</h1>
<div id="info"></div>
<ul>
<li><a href="#goals">Goals</a></li>
<li><a href="#result">Result</a></li>
<li><a href="#example-size-limit">Example: Size Limit</a></li>
<li><a href="#example-size-limit-for-nested-infinite-values">Example: Size Limit for nested infinite values</a></li>
<li><a href="#example-size-limit-for-constructors">Example: Size Limit for constructors</a></li>
<li><a href="#example-time-limits">Example: Time Limits</a></li>
<li><a href="#example-escaping-exceptions">Example: Escaping exceptions</a></li>
<li><a href="#example-nested-errors">Example: Nested errors</a></li>
<li><a href="#example-strings">Example: Strings</a></li>
<li><a href="#example-comparison">Example: Comparison</a></li>
<li><a href="#example-undecidable-comparison">Example: Undecidable comparison</a></li>
<li><a href="#example-highlighting-differences">Example: Highlighting differences</a></li>
<li><a href="#complex-example">Complex Example</a></li>
<li><a href="#implementation-decisions">Implementation Decisions</a></li>
</ul>
</div>
<div class="section level1" id="goals">
<h1><a href="#goals">Goals</a></h1>
<ol style="list-style-type: decimal">
<li>Prettyprinting Haskell values
<ul>
<li>Size limit for the output</li>
<li>Time limit for the computation</li>
<li>Escape exceptions</li>
<li>Do not escape unicode characters</li>
</ul></li>
<li>Comparing Haskell values
<ul>
<li>Highlight the first difference</li>
<li>Yes / No / Maybe results</li>
</ul></li>
</ol>
<p>Intended original use: Help students with automatically tested exercises.</p>
</div>
<div class="section level1" id="result">
<h1><a href="#result">Result</a></h1>
<p><a href="http://hackage.haskell.org/package/data-pprint"><code>data-pprint</code> package on HackageDB</a></p>
<p>The main module is <code>Data.PPrint</code>.</p>
<p>Two main functions:</p>
<pre><code>pprint :: Data a =&gt; a -&gt; IO Doc

(===)  :: Data a =&gt; a -&gt; a -&gt; IO Doc</code></pre>
</div>
<div class="section level1" id="example-size-limit">
<h1><a href="#example-size-limit">Example: Size Limit</a></h1>
<p>In GHCi:</p>
<pre><code>Data.PPrint&gt; pprint [1..]

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, …, ……]</code></pre>
<p>You can try it online!<br />Just edit the text after “Test&gt;”! (<code>pprint</code> is added automatically)</p>
<div class="indent"><form class="resetinterpreter" action="javascript:getOne('c=eval&amp;f=Show_en.hs','0a8d9ed9cdcaf6170f93c0d7e2745602','0a8d9ed9cdcaf6170f93c0d7e2745602');"><code class="prompt">Test&gt; </code><input class="interpreter" type="text" size="60" maxlength="1000" id="tarea0a8d9ed9cdcaf6170f93c0d7e2745602" value="[1..]" /><br /><div class="answer" id="res0a8d9ed9cdcaf6170f93c0d7e2745602"><pre class="normal"><code class="result">[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103,
 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
 130, 131, 132, 133, 134, 135, &#8230;&#8230;]</code></pre><code> :: </code><code class="type">[Integer]</code></div></form></div>
</div>
<div class="section level1" id="example-size-limit-for-nested-infinite-values">
<h1><a href="#example-size-limit-for-nested-infinite-values">Example: Size Limit for nested infinite values</a></h1>
<div class="indent"><form class="resetinterpreter" action="javascript:getOne('c=eval&amp;f=Show_en.hs','19e940082fa55c6841e33d57d7d68ad0','19e940082fa55c6841e33d57d7d68ad0');"><code class="prompt">Test&gt; </code><input class="interpreter" type="text" size="60" maxlength="1000" id="tarea19e940082fa55c6841e33d57d7d68ad0" value="repeat [1..]" /><br /><div class="answer" id="res19e940082fa55c6841e33d57d7d68ad0"><pre class="normal"><code class="result">[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, &#8230;,
  &#8230;&#8230;],
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, &#8230;, &#8230;&#8230;],
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, &#8230;, &#8230;&#8230;],
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, &#8230;, &#8230;&#8230;],
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &#8230;, &#8230;&#8230;],
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &#8230;, &#8230;&#8230;],
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, &#8230;, &#8230;&#8230;],
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, &#8230;, &#8230;&#8230;],
 [1, 2, 3, 4, 5, 6, 7, 8, 9, &#8230;, &#8230;&#8230;],
 [1, 2, 3, 4, 5, 6, 7, 8, &#8230;, &#8230;&#8230;], [1, 2, 3, 4, 5, 6, 7, &#8230;, &#8230;&#8230;],
 [1, 2, 3, 4, 5, 6, &#8230;, &#8230;&#8230;], [1, 2, 3, 4, 5, &#8230;, &#8230;&#8230;],
 [1, 2, 3, 4, &#8230;, &#8230;&#8230;], [1, 2, 3, &#8230;, &#8230;&#8230;], [1, 2, &#8230;, &#8230;&#8230;], [1, &#8230;, &#8230;&#8230;],
 [&#8230;, &#8230;&#8230;], &#8230;, &#8230;&#8230;]</code></pre><code> :: </code><code class="type">[[Integer]]</code></div></form></div>
</div>
<div class="section level1" id="example-size-limit-for-constructors">
<h1><a href="#example-size-limit-for-constructors">Example: Size Limit for constructors</a></h1>
<div class="indent"><form class="resetinterpreter" action="javascript:getOne('c=eval&amp;f=Show_en.hs','c17b35da3df0e19c3fd9b5c32da9b93e','c17b35da3df0e19c3fd9b5c32da9b93e');"><code class="prompt">Test&gt; </code><input class="interpreter" type="text" size="60" maxlength="1000" id="tareac17b35da3df0e19c3fd9b5c32da9b93e" value="iterate (*10) 1" /><br /><div class="answer" id="resc17b35da3df0e19c3fd9b5c32da9b93e"><pre class="normal"><code class="result">[1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
 1000000000, 10000000000, 100000000000, 1000000000000,
 10000000000000, 100000000000000, 1000000000000000,
 10000000000000000, 100000000000000000, 1000000000000000000,
 10000000000000000000, 100000000000000000000,
 1000000000000000000000, 10000000000000000000000,
 100000000000000000000000, 1000000000000000000000000,
 10000000000000000000000000, 100000000000000000000000000,
 1000000000000000000000000000, 10000000000000000000000000000,
 100000000000000000000000000000, 1000000000000000000000000000000,
 10000000000000000000000000000000,
 100000000000000000000000000000000,
 1000000000000000000000000000000000, 1000&#8230;000, &#8230;&#8230;]</code></pre><code> :: </code><code class="type">[Integer]</code></div></form></div>
</div>
<div class="section level1" id="example-time-limits">
<h1><a href="#example-time-limits">Example: Time Limits</a></h1>
<div class="indent"><form class="resetinterpreter" action="javascript:getOne('c=eval&amp;f=Show_en.hs','31c10d8d26f624d078adcb5125794a2a','31c10d8d26f624d078adcb5125794a2a');"><code class="prompt">Test&gt; </code><input class="interpreter" type="text" size="60" maxlength="1000" id="tarea31c10d8d26f624d078adcb5125794a2a" value="map length $ replicate 3 [1..] ++ repeat []" /><br /><div class="answer" id="res31c10d8d26f624d078adcb5125794a2a"><code class="result">[&#8869;&#8321;, &#8869;&#8321;, &#8869;&#8322;, 0, 0, 0, 0, 0, 0, 0, &#8869;&#8323;] ++ &#8869;&#8323;</code><code> :: </code><code class="type">[Int]</code><br /><div class="error">  &#8869;&#8321;: timeout at 0%<br />  &#8869;&#8322;: timeout at 6%<br />  &#8869;&#8323;: timeout at 100%</div></div></form></div>
</div>
<div class="section level1" id="example-escaping-exceptions">
<h1><a href="#example-escaping-exceptions">Example: Escaping exceptions</a></h1>
<div class="indent"><form class="resetinterpreter" action="javascript:getOne('c=eval&amp;f=Show_en.hs','651606dbd50e40f6d690c059adbc4f6f','651606dbd50e40f6d690c059adbc4f6f');"><code class="prompt">Test&gt; </code><input class="interpreter" type="text" size="60" maxlength="1000" id="tarea651606dbd50e40f6d690c059adbc4f6f" value="[2 `div` 0, error &quot;xxx&quot;, 18, 4 `div` 0]" /><br /><div class="answer" id="res651606dbd50e40f6d690c059adbc4f6f"><code class="result">[&#8869;&#8321;, &#8869;&#8322;, 18, &#8869;&#8321;]</code><code> :: </code><code class="type">[Integer]</code><br /><div class="error">  &#8869;&#8321;: &quot;divide by zero&quot;<br />  &#8869;&#8322;: &quot;xxx&quot;</div></div></form></div>
</div>
<div class="section level1" id="example-nested-errors">
<h1><a href="#example-nested-errors">Example: Nested errors</a></h1>
<div class="indent"><form class="resetinterpreter" action="javascript:getOne('c=eval&amp;f=Show_en.hs','d7936cf82269a7c7154e3b1e18d33a04','d7936cf82269a7c7154e3b1e18d33a04');"><code class="prompt">Test&gt; </code><input class="interpreter" type="text" size="60" maxlength="1000" id="taread7936cf82269a7c7154e3b1e18d33a04" value="error (&quot;xx&quot; ++ show (length [1..]))" /><br /><div class="answer" id="resd7936cf82269a7c7154e3b1e18d33a04"><code class="result">&#8869;&#8322;</code><code> :: </code><code class="type">()</code><br /><div class="error">  &#8869;&#8321;: timeout at 0%<br />  &#8869;&#8322;: &quot;xx&quot; ++ &#8869;&#8321;</div></div></form></div>
<div class="indent"><form class="resetinterpreter" action="javascript:getOne('c=eval&amp;f=Show_en.hs','82c5cf5a2e683f45411af4d4c29618df','82c5cf5a2e683f45411af4d4c29618df');"><code class="prompt">Test&gt; </code><input class="interpreter" type="text" size="60" maxlength="1000" id="tarea82c5cf5a2e683f45411af4d4c29618df" value="error (&quot;xx&quot; ++ error &quot;yy&quot;)" /><br /><div class="answer" id="res82c5cf5a2e683f45411af4d4c29618df"><code class="result">&#8869;&#8322;</code><code> :: </code><code class="type">()</code><br /><div class="error">  &#8869;&#8321;: &quot;yy&quot;<br />  &#8869;&#8322;: &quot;xx&quot; ++ &#8869;&#8321;</div></div></form></div>
<div class="indent"><form class="resetinterpreter" action="javascript:getOne('c=eval&amp;f=Show_en.hs','eb09d5f846eaa3c78cc6d89880d19629','eb09d5f846eaa3c78cc6d89880d19629');"><code class="prompt">Test&gt; </code><input class="interpreter" type="text" size="60" maxlength="1000" id="tareaeb09d5f846eaa3c78cc6d89880d19629" value="error $ replicate 10000 'x'" /><br /><div class="answer" id="reseb09d5f846eaa3c78cc6d89880d19629"><code class="result">&#8869;&#8321;</code><code> :: </code><code class="type">()</code><br /><div class="error">  &#8869;&#8321;: <pre class="normal">&quot;x&quot; ++ [&#8230;] ++
&quot;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&quot;
++ [&#8230;, &#8230;&#8230;]</pre></div></div></form></div>
</div>
<div class="section level1" id="example-strings">
<h1><a href="#example-strings">Example: Strings</a></h1>
<div class="indent"><form class="resetinterpreter" action="javascript:getOne('c=eval&amp;f=Show_en.hs','b3b50b68fffc045d386ddebc979925cf','b3b50b68fffc045d386ddebc979925cf');"><code class="prompt">Test&gt; </code><input class="interpreter" type="text" size="60" maxlength="1000" id="tareab3b50b68fffc045d386ddebc979925cf" value="['&#192;'..]" /><br /><div class="answer" id="resb3b50b68fffc045d386ddebc979925cf"><pre class="normal"><code class="result">&quot;&#192;&quot; ++ [&#8230;] ++
&quot;&#194;&#195;&#196;&#197;&#198;&#199;&#200;&#201;&#202;&#203;&#204;&#205;&#206;&#207;&#208;&#209;&#210;&#211;&#212;&#213;&#214;&#215;&#216;&#217;&#218;&#219;&#220;&#221;&#222;&#223;&#224;&#225;&#226;&#227;&#228;&#229;&#230;&#231;&#232;&#233;&#234;&#235;&#236;&#237;&#238;&#239;&#240;&#241;&#242;&#243;&#244;&#245;&#246;&#247;&#248;&#249;&#250;&#251;&#252;&#253;&#254;&#255;&#256;&#257;&#258;&#259;&#260;&#261;&#262;&#263;&#264;&#265;&#266;&#267;&#268;&#269;&#270;&#271;&#272;&#273;&#274;&#275;&#276;&#277;&#278;&#279;&#280;&#281;&#282;&#283;&#284;&#285;&#286;&#287;&#288;&#289;&#290;&#291;&#292;&#293;&#294;&#295;&#296;&#297;&#298;&#299;&#300;&#301;&#302;&#303;&#304;&#305;&#306;&#307;&#308;&#309;&#310;&#311;&#312;&#313;&#314;&#315;&#316;&#317;&#318;&#319;&#320;&#321;&#322;&#323;&#324;&#325;&#326;&#327;&#328;&#329;&#330;&#331;&#332;&#333;&#334;&#335;&#336;&#337;&#338;&#339;&#340;&#341;&#342;&#343;&#344;&#345;&#346;&#347;&#348;&#349;&#350;&#351;&#352;&#353;&#354;&#355;&#356;&#357;&#358;&#359;&#360;&#361;&#362;&#363;&#364;&#365;&#366;&quot;
++ [&#8230;, &#8230;&#8230;]</code></pre><code> :: </code><code class="type">[Char]</code></div></form></div>
<div class="indent"><form class="resetinterpreter" action="javascript:getOne('c=eval&amp;f=Show_en.hs','a4db498ceb6fb8c8c327180a0ea1cacb','a4db498ceb6fb8c8c327180a0ea1cacb');"><code class="prompt">Test&gt; </code><input class="interpreter" type="text" size="60" maxlength="1000" id="tareaa4db498ceb6fb8c8c327180a0ea1cacb" value="&quot;hello&quot; ++ [undefined] ++ &quot;world!&quot;" /><br /><div class="answer" id="resa4db498ceb6fb8c8c327180a0ea1cacb"><code class="result">&quot;hello&quot; ++ [&#8869;&#8321;] ++ &quot;world!&quot;</code><code> :: </code><code class="type">[Char]</code><br /><div class="error">  &#8869;&#8321;: &quot;Prelude.undefined&quot;</div></div></form></div>
</div>
<div class="section level1" id="example-comparison">
<h1><a href="#example-comparison">Example: Comparison</a></h1>
<p>In GHCi:</p>
<pre><code>Data.PPrint&gt; reverse [1..10] === [10,9..1]

    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] === [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Data.PPrint&gt; reverse [1..10] === [10..1]

    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] =/= []</code></pre>
<p>You can try <code>(===)</code> online but only in an implicit way…</p>
<p>Exercise: Define the first 10 square numbers!</p>
<div class="indent"><form class="interpreter" action="javascript:getOne('c=eval&amp;f=Show_en_b9dc82c59873a6aa9799ccde48535746.hs','b9dc82c59873a6aa9799ccde48535746','b9dc82c59873a6aa9799ccde48535746');"><code class="prompt">Solution&gt; </code><input class="interpreter" type="text" size="60" maxlength="1000" id="tareab9dc82c59873a6aa9799ccde48535746" value="" /><br /><div class="answer" id="resb9dc82c59873a6aa9799ccde48535746"></div></form></div>
</div>
<div class="section level1" id="example-undecidable-comparison">
<h1><a href="#example-undecidable-comparison">Example: Undecidable comparison</a></h1>
<pre><code>Data.PPrint&gt; reverse [10..] === [1..]

    ⊥₁ =?= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] ++ ⊥₂
  ⊥₁: timeout at 0%
  ⊥₂: timeout at 100%</code></pre>
</div>
<div class="section level1" id="example-highlighting-differences">
<h1><a href="#example-highlighting-differences">Example: Highlighting differences</a></h1>
<pre><code>Data.PPrint&gt; [1..] === [1..99] ++ [101..]

    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, …, ……, 99, 100, 101, 102,
     103, 104, 105, 106, 107, …, ……]
=/= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, …, ……, 99, 101, 102, 103,
     104, 105, 106, 107, 108, …, ……]


Data.PPrint&gt; ([1..], [1..]) === ([1..], [1..100]) 

    ([1, 2, 3, 4, 5, 6, 7, 8, …, ……],
     [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, …, ……, 99, 100, 101, 102, 103, 104,
      105, 106, 107, …, ……])
=/= ([1, 2, 3, 4, 5, 6, 7, 8, …, ……],
     [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, …, ……, 99, 100])</code></pre>
</div>
<div class="section level1" id="complex-example">
<h1><a href="#complex-example">Complex Example</a></h1>
<pre><code>Data.PPrint&gt; (error &quot;x&quot;, [1..]) === (0 `div` 0, reverse [1..])

    (⊥₁, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] ++ ⊥₂) =?= (⊥₃, ⊥₄)
  ⊥₁: x
  ⊥₂: timeout at 100%
  ⊥₃: divide by zero
  ⊥₄: timeout at 0%</code></pre>
</div>
<div class="section level1" id="implementation-decisions">
<h1><a href="#implementation-decisions">Implementation Decisions</a></h1>
<p>Why <code>Data</code> instance and not <code>Show</code>?</p>
<ul>
<li><code>Data</code> typeclass gives more information</li>
<li>More idiomatic: <code>Data</code> is for “values”</li>
<li>Drawback: Cannot evaluate <code>pprint undefined</code></li>
</ul>
</div>
<div><h1><a href="Overview_en.xml">Back to the main page</a></h1>
<p><em><a href="Overview_en.xml">Main page</a></em></p>
</div>
</body>
</html>

