<br><br>
<div><span class="gmail_quote">On 2/19/08, <b class="gmail_sendername">Ryan Ingram</b> &lt;<a href="mailto:ryani.spam@gmail.com" target="_blank">ryani.spam@gmail.com</a>&gt; wrote:</span> 
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">Oleg&#39;s done a lot of work here; there&#39;s a bunch of magic that can be<br>done with TypeCast.&nbsp;&nbsp;I took my inspiration from here:<br>


<a href="http://okmij.org/ftp/Haskell/typecast.html#ambiguity-resolution" target="_blank">http://okmij.org/ftp/Haskell/typecast.html#ambiguity-resolution</a></blockquote>

<div>
<div>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div>
<div>&nbsp;</div>
<div>. . .</div>
<div>&nbsp;</div></div></blockquote>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">The trick is to represent whether a type is boxed or not via a<br>type-level boolean, which you can then use to affect the instance<br>


selecton.</blockquote>
<div>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div>&nbsp;</div>
<div>. . .</div></blockquote>
<div>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<div>&nbsp;</div></blockquote></div>
<div>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">-- Magic toolbox that solves everything! &nbsp;Thanks Oleg!<br><br>data HTrue<br>data HFalse<br>

<br>class TypeCast &nbsp; a b &nbsp; | a -&gt; b, b-&gt;a &nbsp; where typeCast &nbsp; :: a -&gt; b<br>
class TypeCast&#39; &nbsp;t a b | t a -&gt; b, t b -&gt; a where typeCast&#39; &nbsp;:: t-&gt;a-&gt;b<br>class TypeCast&#39;&#39; t a b | t a -&gt; b, t b -&gt; a where typeCast&#39;&#39; :: t-&gt;a-&gt;b<br>instance TypeCast&#39; &nbsp;() a b =&gt; TypeCast a b where typeCast x = typeCast&#39; () x<br>


instance TypeCast&#39;&#39; t a b =&gt; TypeCast&#39; t a b where typeCast&#39; = typeCast&#39;&#39;<br>instance TypeCast&#39;&#39; () a a where typeCast&#39;&#39; _ x &nbsp;= x<br></blockquote></div></div></div></div></div>
<div><br>Thanks for showing me this technique.&nbsp; I studied your code for several hours.&nbsp; And, I&#39;ve read Oleg&#39;s &quot;Strongly Typed Heterogeneous Collections.&quot;&nbsp; <br></div><br>As a learning exercise, I modified your code.&nbsp; I managed to shorten it a bit, but I had a couple of surprises.&nbsp; Please see my comments in the code below.<br>
<br><span style="font-family: courier new,monospace;">{-# OPTIONS_GHC</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp; -fglasgow-exts</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&nbsp;&nbsp; -fbreak-on-exception</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp; -fallow-undecidable-instances</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&nbsp;&nbsp; -fallow-overlapping-instances</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">#-}</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">module SmartArray where</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">import IO</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">import Data.Ix</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">import Data.Array.Unboxed</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">import Data.Complex</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">type SmartArray i e = (Ix i, SmartArraySelector a e) =&gt; (a i e)</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- smartArray is similar to array function from Data.Array. But,</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- it will return a UArray if e can be unboxed.&nbsp; Otherwise, it</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">-- returns an Array.</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">smartArray :: (i, i) -&gt; [(i, e)] -&gt; SmartArray i e</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">smartArray bnd eLst = array bnd eLst</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">class ArrTypeCast a b | a -&gt; b, b-&gt;a where</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; arrTypeCast :: a i e -&gt; b i e</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">instance ArrTypeCast x x where</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; arrTypeCast = id</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- SURPRISE 1: If function, arrTypeCast, is removed, (from both</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">-- the class and instance) GHC assumes the kind of a and b are *,</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- instead of * -&gt; * -&gt; * and produce . . .&nbsp; </span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">--</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- report3.hs:37:24:</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">--&nbsp;&nbsp;&nbsp;&nbsp; `UArray&#39; is not applied to enough type arguments</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">--&nbsp;&nbsp;&nbsp;&nbsp; Expected kind `*&#39;, but `UArray&#39; has kind `* -&gt; * -&gt; *&#39;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">--&nbsp;&nbsp;&nbsp;&nbsp; In the type `(ArrTypeCast a UArray, IArray a Bool) =&gt;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SmartArraySelector a Bool&#39;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">--&nbsp;&nbsp;&nbsp;&nbsp; In the instance declaration for `SmartArraySelector a Bool&#39;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">--</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">-- It appears that functions defined in a class can constrain the</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- type variables of the class.&nbsp; To me, this seems a bit magical</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">-- and unexpected.</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">class (IArray a e) =&gt; SmartArraySelector a e | e -&gt; a</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- instances of SmartArraySelector for all boxed types (For</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- breivity, not all unboxed types are listed.)</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">instance (ArrTypeCast a UArray, IArray a Bool) </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; =&gt; SmartArraySelector a Bool</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">instance (ArrTypeCast a UArray, IArray a Char) </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; =&gt; SmartArraySelector a Char</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">instance (ArrTypeCast a UArray, IArray a Double) </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; =&gt; SmartArraySelector a Double</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">instance (ArrTypeCast a UArray, IArray a Float) </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; =&gt; SmartArraySelector a Float</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">instance (ArrTypeCast a UArray, IArray a Int) </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; =&gt; SmartArraySelector a Int</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- SURPRISE 2: The class SmartArraySelector has the type</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- assertion, (IArray a e).&nbsp; It seems like adding an additional<br>
-- IArray</span> <span style="font-family: courier new,monospace;">assertion to each instance is redundant.&nbsp; However, <br>-- if I remove</span><span style="font-family: courier new,monospace;"> the assertion (IArray a Int) above, GHC <br>
-- reports . . .</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">-- report3.hs:37:24:</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">--&nbsp;&nbsp;&nbsp;&nbsp; `UArray&#39; is not applied to enough type arguments</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">--&nbsp;&nbsp;&nbsp;&nbsp; Expected kind `*&#39;, but `UArray&#39; has kind `* -&gt; * -&gt; *&#39;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">--&nbsp;&nbsp;&nbsp;&nbsp; In the type `(ArrTypeCast a UArray, IArray a Bool) =&gt;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">--&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SmartArraySelector a Bool&#39;</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">--&nbsp;&nbsp;&nbsp;&nbsp; In the instance declaration for `SmartArraySelector a Bool&#39;</span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">--</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">-- Why is this second type assertion required?</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">instance (ArrTypeCast a Array, IArray a b) </span><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">&nbsp;&nbsp;&nbsp; =&gt; SmartArraySelector a b</span><br style="font-family: courier new,monospace;">
<br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;"><span style="font-family: courier new,monospace;">test :: SmartArraySelector a e =&gt; e -&gt; a Int e</span><br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;">test e = smartArray (0,10) [ (i,e) | i &lt;- [0..10]]</span><br style="font-family: courier new,monospace;"><br style="font-family: courier new,monospace;">I&#39;d love to find a good article that describes the ins and outs of multi parameter types, functional dependencies, and type assertions, in enough detail to resolve these surprises.&nbsp; A step-by-step walk through showing how the compiler resolve a type and selects an instance would be awesome.&nbsp; <br>
<br>Usually, when I&#39;m having trouble getting Haskell&#39;s type system to do what I want, I resort to trial and error tactics.&nbsp; I wish I had a better foundation so I could take a more intelligent approach to type hacking.<br style="font-family: courier new,monospace;">
<span style="font-family: courier new,monospace;"></span><br style="font-family: courier new,monospace;">