If I'm interpreting your code properly, it's not currently catching that case anyway.<div><br>The problem is that you've got two sets of modifiers that both should be optimized, explicit Modifier constructors in the Image, and a list contained in Changes. Since 'Changes' 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 'deBlank', but then the rules from 'optimize' aren't applied. You can'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'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 'Modifier x' from 'optimize' into 'deBlank'. Then you would have something like this:<br><br>> deBlank :: [Modifier] -> [Modifier]<br>
> deBlank = db</div><div>> </div><div>> db (Scale 1 1 : l) = db l<br>> db (Rotate x : Rotate x' : l) = db (Rotate (x+x') : l)<br>> db (Scale x y : Scale x' y' : l) = db (Scale (x*x') (y*y') : l)<br>
> db (Translate x y : Translate x' y' : l) = db (Translate (x+x') (y+y') : l)<br>> db xs = xs<br></div><div><br></div><div>I actually don'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've provided), and you can use it within a two-pass optimize:</div><div><br></div><div>> optimize = transform o2 . transform o</div>
<div>> </div><div>> o (Modifier _ Blank) = Blank</div><div>> o (Modifier (Scale 0 _) _i) = Blank</div><div>> -- similar cases omitted</div><div>> </div><div>> o (Modifier m2 (Modifier m1 i)) = Modifier (m1 `mappend` m2) i</div>
<div>> o i@(Modifier (Changes _c) _i) = i</div><div>> o (Modifier m i) = Modifier (Changes [m]) i</div><div>> o i = i</div><div>></div><div>> o2 (Modifier (Changes c) i) = case deBlank c of</div><div>> [] -> i</div>
<div>> [x] -> Modifier x i</div><div>> xs -> Modifier (Changes c) i</div><div>> o2 i = i</div><div><br></div><div>Transformations like "Scale 0 _" 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 'deBlank' function instead of split between there and 'o'.</div>
<div><br></div><div>This presumes there's an appropriate Monoid instance for Modifiers, but if it doesn'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>> o (Modifier _ Blank) = Blank</div><div>> o (Modifier (Scale 0 _) _i) = Blank</div></div><div><br></div><div>as a third pass, because it's possible some of them could get lost in this form. Then the first pass would just combine terms, the second would apply 'deBlank' 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 "Changes c" 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 <<a href="mailto:maydwell@gmail.com">maydwell@gmail.com</a>> wrote:<br>><br>> The fixpoint nature of rewrite catches some cases that transform might<br>
> not if I'm interpreting it correctly.<br>><br>> (Changes [Translate 1 1, Scale 1 1, Translate 1 1]) could be rewritten<br>> as (Translate 2 2), but I'm not sure that it could be translated as<br>> such if it matches against (Changes [Translate _ _, Translate _ _])<br>
> first.<br>><br>> I have the code on github at<br>> <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>
> if you're interested.<br>><br>> At the moment I'm not worrying about speed as I really just wrote this<br>> optimisation function as a demo of why an AST interface to Diagrams<br>> might be useful.<br>
><br>> On Tue, Jun 7, 2011 at 5:06 PM, John Lato <<a href="mailto:jwlato@gmail.com">jwlato@gmail.com</a>> wrote:<br>> > Is it necessary (helpful) to use 'rewrite'? Nearly every time I've tried<br>
> > it, in the end 'transform' has been a better choice. Then you wouldn't need<br>> > the 'Just's at all, and it should work fine.<br>> > John<br>> ><br>> >><br>> >> From: Lyndon Maydwell <<a href="mailto:maydwell@gmail.com">maydwell@gmail.com</a>><br>
> >><br>> >> (missed including cafe)<br>> >><br>> >> f :: [Modification] -> Maybe [Modification]<br>> >> and<br>> >> f _ = Just $ f ...<br>> >> are incompatible<br>
> >><br>> >> I managed to get the behaviour I'm after with the use of Either, but<br>> >> this really is messy:<br>> >><br>> >><br>> >> -- Sets of changes<br>> >> o (Modifier (Changes []) i) = Just $ i<br>
> >> o (Modifier (Changes [c]) i) = Just $ Modifier c i<br>> >> o (Modifier (Changes l) i) = g (f (Left l))<br>> >> where<br>> >> g (Right l) = Just $ Modifier (Changes l) i<br>> >> g (Left l) = Nothing<br>
> >><br>> >> f (Left (Scale x y : Scale x' y' : l)) =<br>> >> f $ Right $ Scale (x*x') (y*y') : h (f $ Left l)<br>> >> f (Left (Translate x y : Translate x' y' : l)) =<br>
> >> f $ Right $ Translate (x+x') (y+y') : h (f $ Left l)<br>> >> f (Left (Rotate x : Rotate x' : l)) =<br>> >> f $ Right $ Rotate (x+x') : h (f $ Left l)<br>
> >> f x = x<br>> >><br>> >> h (Left l) = l<br>> >> h (Right l) = l<br>> >><br>> >><br>> >> On Tue, Jun 7, 2011 at 3:11 AM, Maciej Marcin Piechotka<br>
> >> <<a href="mailto:uzytkownik2@gmail.com">uzytkownik2@gmail.com</a>> wrote:<br>> >> > On Mon, 2011-06-06 at 23:38 +0800, Lyndon Maydwell wrote:<br>> >> >> I'm writing an optimisation routine using Uniplate. Unfortunately, a<br>
> >> >> sub-function I'm writing is getting caught in an infinite loop because<br>> >> >> it doesn't return Nothing when there are no optimisations left.<br>> >> >><br>
> >> >> I'd like a way to move the last Just into f, but this makes recursion<br>> >> >> very messy. I was wondering if there was a nice way to use something<br>> >> >> like the Monad or Applicative instance to help here.<br>
> >> >><br>> >> >> -- Sets of changes<br>> >> >> o (Modifier (Changes []) ?i) = Just $ i<br>> >> >> o (Modifier (Changes [c]) i) = Just $ Modifier c i<br>> >> >> o (Modifier (Changes l) ? i) = Just $ Modifier (Changes (f l)) i<br>
> >> >> ? where<br>> >> >> ? ? f (Scale ? ? x y : Scale ? ? x' y' : l) = f $ Scale ? ? (x*x')<br>> >> >> (y*y') : f l<br>> >> >> ? ? f (Translate x y : Translate x' y' : l) = f $ Translate (x+x')<br>
> >> >> (y+y') : f l<br>> >> >> ? ? f (Rotate ? ?x ? : Rotate ? ?x' ? ?: l) = f $ Rotate ? ?(x+x') ? ?<br>> >> >> ? ?: f l<br>> >> >> ? ? f l = l<br>
> >> >><br>> >> >><br>> >> >> Any ideas?<br>> >> ><br>> >> > Something like:<br>> >> ><br>> >> > ...<br>> >> > f (Rotate ? ?x ? : Rotate ? ?x' ? ?: l)<br>
> >> > ? ?= Just $ f (Rotate (x+x') : fromMaybe l (f l))<br>> >> > f l = Nothing -- As far as I understend<br>> >> ><br>> >> > Regards<br>> >> ><br>> >> > _______________________________________________<br>
> ><br><br></div>