If I&#39;m interpreting your code properly, it&#39;s not currently catching that case anyway.<div><br>The problem is that you&#39;ve got two sets of modifiers that both should be optimized, explicit Modifier constructors in the Image, and a list contained in Changes.  Since &#39;Changes&#39; is just a list of Modifiers, and not an Image, neither rewrite nor transform will descend on it.  You get around this by explicitly calling rewrite on the modifiers in &#39;deBlank&#39;, but then the rules from &#39;optimize&#39; aren&#39;t applied.  You can&#39;t really use the biplate functions either because they only match on a single element at a time.  What you really want to do is be able to express each rule exactly once, which isn&#39;t possible in the current form of your code.</div>
<div><br>One solution is to move a lot of the reductions of the form &#39;Modifier x&#39; from &#39;optimize&#39; into &#39;deBlank&#39;.  Then you would have something like this:<br><br>&gt; deBlank :: [Modifier] -&gt; [Modifier]<br>
&gt; deBlank = db</div><div>&gt; </div><div>&gt; db (Scale 1 1 : l)   = db l<br>&gt; db (Rotate x : Rotate x&#39; : l) = db (Rotate (x+x&#39;) : l)<br>&gt; db (Scale  x y : Scale x&#39; y&#39; : l) = db (Scale (x*x&#39;) (y*y&#39;) : l)<br>
&gt; db (Translate x y : Translate x&#39; y&#39; : l) = db (Translate (x+x&#39;) (y+y&#39;) : l)<br>&gt; db xs = xs<br></div><div><br></div><div>I actually don&#39;t think uniplate gets you anything in this particular function.</div>
<div><br></div><div>Now deBlank will produce a list of modifiers which is as reduced as possible (at least by the rules you&#39;ve provided), and you can use it within a two-pass optimize:</div><div><br></div><div>&gt; optimize = transform o2 . transform o</div>
<div>&gt; </div><div>&gt; o (Modifier _ Blank) = Blank</div><div>&gt; o (Modifier (Scale 0 _) _i) = Blank</div><div>&gt; -- similar cases omitted</div><div>&gt; </div><div>&gt; o (Modifier m2 (Modifier m1 i)) = Modifier (m1 `mappend` m2) i</div>
<div>&gt; o i@(Modifier (Changes _c) _i) = i</div><div>&gt; o (Modifier m i) = Modifier (Changes [m]) i</div><div>&gt; o i = i</div><div>&gt;</div><div>&gt; o2 (Modifier (Changes c) i) = case deBlank c of</div><div>&gt;      [] -&gt; i</div>
<div>&gt;      [x] -&gt; Modifier x i</div><div>&gt;      xs -&gt; Modifier (Changes c) i</div><div>&gt; o2 i = i</div><div><br></div><div>Transformations like &quot;Scale 0 _&quot; have remained in the Image traversal, however all other modifications are combined into a single Changes list, which is then reduced by deBlank in the second pass.  Note that in the first pass, even single modifications are encapsulated in a Changes; this makes the logic of the second pass much simpler because then all the reductions of multiple modifiers are located in the &#39;deBlank&#39; function instead of split between there and &#39;o&#39;.</div>
<div><br></div><div>This presumes there&#39;s an appropriate Monoid instance for Modifiers, but if it doesn&#39;t exist it can be written easily enough.</div><div><br></div><div>On second thought, I think it would be good to break it up even more, and keep the reductions of the form</div>
<div><br></div><div><div>&gt; o (Modifier _ Blank) = Blank</div><div>&gt; o (Modifier (Scale 0 _) _i) = Blank</div></div><div><br></div><div>as a third pass, because it&#39;s possible some of them could get lost in this form.  Then  the first pass would just combine terms, the second would apply &#39;deBlank&#39; and reduce, then the third would be as above.</div>
<div><br></div><div>There are two alternatives which may be simpler:</div><div><br></div><div>1)  Expand &quot;Changes c&quot; into explicit modifications and do all your reductions on the resulting Image.</div><div><br></div>
<div>2)   Implement a general matrix transform for Diagrams and rewrite everything in terms of that.  This would be useful for shear transforms anyway, which I believe are currently inexpressible in Diagrams.</div><div><br>
</div><div>John Lato</div><div><br>On Tue, Jun 7, 2011 at 10:12 AM, Lyndon Maydwell &lt;<a href="mailto:maydwell@gmail.com">maydwell@gmail.com</a>&gt; wrote:<br>&gt;<br>&gt; The fixpoint nature of rewrite catches some cases that transform might<br>
&gt; not if I&#39;m interpreting it correctly.<br>&gt;<br>&gt; (Changes [Translate 1 1, Scale 1 1, Translate 1 1]) could be rewritten<br>&gt; as (Translate 2 2), but I&#39;m not sure that it could be translated as<br>&gt; such if it matches against (Changes [Translate _ _, Translate _ _])<br>
&gt; first.<br>&gt;<br>&gt; I have the code on github at<br>&gt; <a href="https://github.com/sordina/Diagrams-AST/blob/master/src/Graphics/Rendering/Diagrams/AST/Optimize.hs">https://github.com/sordina/Diagrams-AST/blob/master/src/Graphics/Rendering/Diagrams/AST/Optimize.hs</a><br>
&gt; if you&#39;re interested.<br>&gt;<br>&gt; At the moment I&#39;m not worrying about speed as I really just wrote this<br>&gt; optimisation function as a demo of why an AST interface to Diagrams<br>&gt; might be useful.<br>
&gt;<br>&gt; On Tue, Jun 7, 2011 at 5:06 PM, John Lato &lt;<a href="mailto:jwlato@gmail.com">jwlato@gmail.com</a>&gt; wrote:<br>&gt; &gt; Is it necessary (helpful) to use &#39;rewrite&#39;?  Nearly every time I&#39;ve tried<br>
&gt; &gt; it, in the end &#39;transform&#39; has been a better choice.  Then you wouldn&#39;t need<br>&gt; &gt; the &#39;Just&#39;s at all, and it should work fine.<br>&gt; &gt; John<br>&gt; &gt;<br>&gt; &gt;&gt;<br>&gt; &gt;&gt; From: Lyndon Maydwell &lt;<a href="mailto:maydwell@gmail.com">maydwell@gmail.com</a>&gt;<br>
&gt; &gt;&gt;<br>&gt; &gt;&gt; (missed including cafe)<br>&gt; &gt;&gt;<br>&gt; &gt;&gt; f :: [Modification] -&gt; Maybe [Modification]<br>&gt; &gt;&gt; and<br>&gt; &gt;&gt; f _ = Just $ f ...<br>&gt; &gt;&gt; are incompatible<br>
&gt; &gt;&gt;<br>&gt; &gt;&gt; I managed to get the behaviour I&#39;m after with the use of Either, but<br>&gt; &gt;&gt; this really is messy:<br>&gt; &gt;&gt;<br>&gt; &gt;&gt;<br>&gt; &gt;&gt; -- Sets of changes<br>&gt; &gt;&gt; o (Modifier (Changes [])  i) = Just $ i<br>
&gt; &gt;&gt; o (Modifier (Changes [c]) i) = Just $ Modifier c i<br>&gt; &gt;&gt; o (Modifier (Changes l)   i) = g (f (Left l))<br>&gt; &gt;&gt;  where<br>&gt; &gt;&gt;    g (Right l) = Just $ Modifier (Changes l) i<br>&gt; &gt;&gt;    g (Left  l) = Nothing<br>
&gt; &gt;&gt;<br>&gt; &gt;&gt;    f (Left  (Scale     x y : Scale     x&#39; y&#39; : l)) =<br>&gt; &gt;&gt;        f $ Right $ Scale     (x*x&#39;) (y*y&#39;) : h (f $ Left l)<br>&gt; &gt;&gt;    f (Left  (Translate x y : Translate x&#39; y&#39; : l)) =<br>
&gt; &gt;&gt;        f $ Right $ Translate (x+x&#39;) (y+y&#39;) : h (f $ Left l)<br>&gt; &gt;&gt;    f (Left  (Rotate    x   : Rotate    x&#39;    : l)) =<br>&gt; &gt;&gt;        f $ Right $ Rotate    (x+x&#39;)        : h (f $ Left l)<br>
&gt; &gt;&gt;    f x = x<br>&gt; &gt;&gt;<br>&gt; &gt;&gt;    h (Left  l) = l<br>&gt; &gt;&gt;    h (Right l) = l<br>&gt; &gt;&gt;<br>&gt; &gt;&gt;<br>&gt; &gt;&gt; On Tue, Jun 7, 2011 at 3:11 AM, Maciej Marcin Piechotka<br>
&gt; &gt;&gt; &lt;<a href="mailto:uzytkownik2@gmail.com">uzytkownik2@gmail.com</a>&gt; wrote:<br>&gt; &gt;&gt; &gt; On Mon, 2011-06-06 at 23:38 +0800, Lyndon Maydwell wrote:<br>&gt; &gt;&gt; &gt;&gt; I&#39;m writing an optimisation routine using Uniplate. Unfortunately, a<br>
&gt; &gt;&gt; &gt;&gt; sub-function I&#39;m writing is getting caught in an infinite loop because<br>&gt; &gt;&gt; &gt;&gt; it doesn&#39;t return Nothing when there are no optimisations left.<br>&gt; &gt;&gt; &gt;&gt;<br>
&gt; &gt;&gt; &gt;&gt; I&#39;d like a way to move the last Just into f, but this makes recursion<br>&gt; &gt;&gt; &gt;&gt; very messy. I was wondering if there was a nice way to use something<br>&gt; &gt;&gt; &gt;&gt; like the Monad or Applicative instance to help here.<br>
&gt; &gt;&gt; &gt;&gt;<br>&gt; &gt;&gt; &gt;&gt; -- Sets of changes<br>&gt; &gt;&gt; &gt;&gt; o (Modifier (Changes []) ?i) = Just $ i<br>&gt; &gt;&gt; &gt;&gt; o (Modifier (Changes [c]) i) = Just $ Modifier c i<br>&gt; &gt;&gt; &gt;&gt; o (Modifier (Changes l) ? i) = Just $ Modifier (Changes (f l)) i<br>
&gt; &gt;&gt; &gt;&gt; ? where<br>&gt; &gt;&gt; &gt;&gt; ? ? f (Scale ? ? x y : Scale ? ? x&#39; y&#39; : l) = f $ Scale ? ? (x*x&#39;)<br>&gt; &gt;&gt; &gt;&gt; (y*y&#39;) : f l<br>&gt; &gt;&gt; &gt;&gt; ? ? f (Translate x y : Translate x&#39; y&#39; : l) = f $ Translate (x+x&#39;)<br>
&gt; &gt;&gt; &gt;&gt; (y+y&#39;) : f l<br>&gt; &gt;&gt; &gt;&gt; ? ? f (Rotate ? ?x ? : Rotate ? ?x&#39; ? ?: l) = f $ Rotate ? ?(x+x&#39;) ? ?<br>&gt; &gt;&gt; &gt;&gt; ? ?: f l<br>&gt; &gt;&gt; &gt;&gt; ? ? f l = l<br>
&gt; &gt;&gt; &gt;&gt;<br>&gt; &gt;&gt; &gt;&gt;<br>&gt; &gt;&gt; &gt;&gt; Any ideas?<br>&gt; &gt;&gt; &gt;<br>&gt; &gt;&gt; &gt; Something like:<br>&gt; &gt;&gt; &gt;<br>&gt; &gt;&gt; &gt; ...<br>&gt; &gt;&gt; &gt; f (Rotate ? ?x ? : Rotate ? ?x&#39; ? ?: l)<br>
&gt; &gt;&gt; &gt; ? ?= Just $ f (Rotate (x+x&#39;) : fromMaybe l (f l))<br>&gt; &gt;&gt; &gt; f l = Nothing -- As far as I understend<br>&gt; &gt;&gt; &gt;<br>&gt; &gt;&gt; &gt; Regards<br>&gt; &gt;&gt; &gt;<br>&gt; &gt;&gt; &gt; _______________________________________________<br>
&gt; &gt;<br><br></div>