On Sun, Dec 21, 2008 at 10:27 AM, Peter Todd <span dir="ltr">&lt;<a href="mailto:pete@petertodd.org">pete@petertodd.org</a>&gt;</span> wrote:<br><div class="gmail_quote"><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="Ih2E3d"><br>
data Element = Element {<br>
 &nbsp; &nbsp;elementOrigin :: V,<br>
 &nbsp; &nbsp;elementSubs :: [Element]<br>
 &nbsp; &nbsp;}<br>
</div> &nbsp; &nbsp;| ElementThunk T Element<br>
<br>
transform :: T -&gt; Element -&gt; Element<br>
transform t (ElementThunk t2 e) = ElementThunk (tmul t t2) e<br>
transform t e = ElementThunk t e<br>
<div class="Ih2E3d">transform t e = Element {<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;elementOrigin = tmulv t (elementOrigin e),<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;elementSubs = map (transform t) (elementSubs e)<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}<br>
<br>
</div>This gives a behavior close to what I want, applying a transform to an<br>
element results in a &quot;thunk&quot;, and subsequent transforms simply modify<br>
the thunk, the problem is that I don&#39;t see a way to implicitly coerce an<br>
ElementThunk into an Element on demand for all the other code in the<br>
program that expects elements. (such as the elementOrigin function)</blockquote><div><br>Oh!&nbsp; Okay, studying your code a bit, I think I finally understand what you&#39;re trying to do.&nbsp; Tell me if I&#39;m wrong.&nbsp; You have a list of elements es and a composition of transforms t1,t2,t3, and instead of applying t1, t2, and t3 to each element, you want to collapse them together into a single matrix and apply that matrix to each element.<br>
<br>This is definitely a modeling level thing to do; you don&#39;t need to go anywhere near rewrite rules or thinking about internal representations or anything like that.&nbsp; A bit of old fashioned abstraction should do the trick.<br>
<br>Your Thunk representation is not that bad.&nbsp; I can&#39;t really weigh the trade-offs for you.&nbsp; Keep the data type abstract and only allow access through functions (like elementOrigin).&nbsp; Then I don&#39;t see the problem with redefining elementOrigin as:<br>
<br><font face="courier new,monospace">elementOrigin (Element v subs) = v<br>elementOrigin (ElementThunk t e) = tmulv t (elementOrigin e)<br><br><font face="times new roman,serif">Keep the number of operations which need to know the representation (constructors) of Element as small as you can.<br>
<br>Another possibility is this:<br><br><font face="courier new,monospace">data Element = Element<br>&nbsp; { elementOrigin :: V<br>&nbsp; , elementSubs :: [(T,Element)]<br>&nbsp; }</font></font></font><br><br><font face="times new roman,serif">Where, of course, the transform for each sub-element is relative.<br>
<br>Overall I think your &quot;thunk&quot; solution is a very nice trade-off.&nbsp; (Minor rhetorical note: I would probably name your ElementThunk constructor Transform or ElementTransform instead)<br><br>Hmm, you have an invariant that the pattern ElementThunk t (ElementThunk t e) never occurs.&nbsp; It would be good style to encode this:<br>
<br><font face="courier new,monospace">data PrimElement = PrimElement { elementOrigin :: V, elementSubs :: [Element] }<br>data Element = Element (Maybe T) PrimElement<br></font><br>That Maybe bugs me.&nbsp; You could factor that out into the T type with a special optimization for the identity transform.&nbsp; Hmm, then the [(T,Element)] encoding and this one are identical.&nbsp; Fun. :-)<br>
<br>Short answer:&nbsp; <i>abstract data type!</i><br></font><br>Luke<br><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
<div class="Ih2E3d"><br>
&gt; By the way, this is very operational thinking for Haskell. &nbsp;Haskell tries<br>
&gt; quite hard to abstract away operational thinking, so thinking on this level<br>
&gt; will be difficult and more work than you should be doing to write a program.<br>
<br>
</div>Yes, but this part of the program is library code, that will be used by<br>
a whole pile of other stuff, so if I can get the right behavior<br>
&quot;magically&quot; the rest of the program will be a lot easier to write.<br>
<br>
FWIW this is EDA software, those &quot;elements&quot; refer to elements of a<br>
printed circuit board layout, and the transform operations correspond to<br>
stuff like moving a chip on the board. The representation of a simple IC<br>
would consist of something like an element, with a bunch of sub-elements<br>
for each pin, all of which have geometry data.<br>
<div class="Ih2E3d"><br>
&gt; May I ask why you want this behavior? &nbsp;Have you just tested it and observed<br>
&gt; that it is running too slowly and you are trying to speed it up?<br>
<br>
</div>I&#39;ve written a previous version of this program in Python actually,<br>
where I explicitly modeled the lazy evaluation behavior that I wanted.<br>
It all worked great, but the overall speed was still quite slow. &nbsp;I was<br>
hoping that Haskell, built around lazy evaluation already, would be a<br>
better fit.<br>
<br>
<br>
That, and in any case, other aspects of the program that I&#39;ve re-written<br>
in Haskell saw about a 5-1 redunction in code length... :)<br>
<div><div></div><div class="Wj3C7c"><br>
--<br>
<a href="http://petertodd.org" target="_blank">http://petertodd.org</a> &#39;peter&#39;[:-1]@<a href="http://petertodd.org" target="_blank">petertodd.org</a><br>
</div></div><br>-----BEGIN PGP SIGNATURE-----<br>
Version: GnuPG v1.4.6 (GNU/Linux)<br>
<br>
iD8DBQFJTnx03bMhDbI9xWQRAhWvAJoD8JeQg/3Q3Oy5FNEAaVjbNDbg3QCfe5jJ<br>
Ob2IGxR4YDfiVpoTeOFcnBM=<br>
=RS6B<br>
-----END PGP SIGNATURE-----<br>
<br></blockquote></div><br>