<div dir="ltr"><div><div><div>There are several ways to approach this problem. What you are basically trying to do is map a function over the leaves of your datastructure. So naturally a function that comes to mind is:<br>
<br>mapBar :: (Integer -> Integer) -> (Float -> Float) -> Bar -> Bar<br>mapBar f _ (Bar1 i) = Bar1 (f i)<br>mapBar _ g (Bar2 r) = Bar2 (g r)<br>mapBar f g (Exp1 e1 e2) = Exp1 (mapBar f g e1) (mapBar f g e2)<br>
mapBar f g (Exp2 e1 e2) = Exp2 (mapBar f g e1) (mapBar f g e2)<br><br></div>And the Bar instance becomes<br><br>instance FooClass Bar where<br>    foo1 = mapBar foo1 foo1<br>    foo2 = mapBar foo2 foo2<br><br></div>As far as I understand this is not what you're looking for, as you want the mapBar function to be agnostic wrt what type the leaves contain. The minimal assumption that this requires is that the leaf types are a member of FooClass, and indeed you can write such a map:<br>
<br>mapBar :: (forall a. FooClass a => a -> a) -> Bar -> Bar<br>mapBar f (Bar1 i) = Bar1 (f i)<br>mapBar f (Bar2 r) = Bar2 (f r)<br>mapBar f (Exp1 e1 e2) = Exp1 (mapBar f e1) (mapBar f e2)<br>mapBar f (Exp2 e1 e2) = Exp2 (mapBar f e1) (mapBar f e2)<br>
<br>instance FooClass Bar where<br>    foo1 = mapBar foo1<br>    foo2 = mapBar foo2<br><br></div>I think this is closer to what you were looking for. The above map requires -XRankNTypes, because mapBar requires a function that is fully polymorphic ('a' will instantiate to Integer and Float respectively). If you haven't used higher ranked types before I think it is instructive to think about why the above signature works and the one you wrote doesn't. In particular think about at which point the polymorphic type 'a' is instantiated in both cases, or rather what the "scope" of 'a' is.<br>
</div><div class="gmail_extra"><br><br><div class="gmail_quote">On 2 December 2013 19:37, TP <span dir="ltr"><<a href="mailto:paratribulations@free.fr" target="_blank">paratribulations@free.fr</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">Vo Minh Thu wrote:<br>
<br>
> You can replace your `propagate` function by this one:<br>
><br>
>     propagate :: Bar -> (Integer -> Integer) -> Bar<br>
>     propagate v f = case v of<br>
>         Bar1 i     -> Bar1 (f i)<br>
>         Exp1 b1 b2 -> Exp1 (propagate b1 f) (propagate b2 f)<br>
>         Exp2 b1 b2 -> Exp2 (propagate b1 f) (propagate b2 f)<br>
><br>
> In your code, you were applying the same (w.r.t. to its type) `f` to<br>
> Bar and Integer.<br>
> Also, your Bar data type contains, at its leaf, an Intger, not a `a`.<br>
<br>
</div>You are right, I made a stupid error in my code. The following version<br>
indeed works:<br>
<div class="im"><br>
----------------<br>
class FooClass a where<br>
    foo1 :: a -> a<br>
    foo2 :: a -> a<br>
<br>
instance FooClass Integer where<br>
<br>
    foo1 v = 1<br>
    foo2 v = 2<br>
<br>
data Bar = Bar1 Integer<br>
         | Exp1 Bar Bar<br>
         | Exp2 Bar Bar<br>
    deriving Show<br>
<br>
</div>-- The following line works because there are only integers in the leaves.<br>
<div class="im">propagate :: Bar -> (Integer -> Integer) -> Bar<br>
propagate v f = case v of<br>
        Bar1 i     -> Bar1 (f i)<br>
        Exp1 b1 b2 -> Exp1 (propagate b1 f) (propagate b2 f)<br>
        Exp2 b1 b2 -> Exp2 (propagate b1 f) (propagate b2 f)<br>
<br>
</div><div class="im">instance FooClass Bar where<br>
<br>
    foo1 b = propagate b foo1<br>
    foo2 b = propagate b foo2<br>
<br>
main = do<br>
<br>
let a = Bar1 3<br>
let b = Bar1 4<br>
let c = Exp1 (Exp2 a b) b<br>
<br>
print c<br>
print $ foo1 c<br>
print $ foo2 c<br>
----------------<br>
<br>
</div>However, if we add another type in the leaves, we cannot use the solution<br>
above.<br>
<div class="im"><br>
----------------<br>
class FooClass a where<br>
    foo1 :: a -> a<br>
    foo2 :: a -> a<br>
<br>
instance FooClass Integer where<br>
<br>
    foo1 v = 1<br>
    foo2 v = 2<br>
<br>
</div>instance FooClass Float where<br>
<br>
    foo1 v = 0.25<br>
    foo2 v = 0.5<br>
<div class="im"><br>
data Bar = Bar1 Integer<br>
</div>         | Bar2 Float<br>
<div class="im">         | Exp1 Bar Bar<br>
         | Exp2 Bar Bar<br>
    deriving Show<br>
<br>
</div>-- This time the following line does not work.<br>
<div class="im">propagate :: Bar -> (Integer -> Integer) -> Bar<br>
</div>-- The following line does not work either.<br>
-- propagate :: FooClass a => Bar -> (a->a) -> Bar<br>
<div class="im">propagate v f = case v of<br>
        Bar1 i     -> Bar1 (f i)<br>
</div>        Bar2 i     -> Bar2 (f i)<br>
<div class="im HOEnZb">        Exp1 b1 b2 -> Exp1 (propagate b1 f) (propagate b2 f)<br>
        Exp2 b1 b2 -> Exp2 (propagate b1 f) (propagate b2 f)<br>
<br>
</div><div class="im HOEnZb">instance FooClass Bar where<br>
<br>
    foo1 b = propagate b foo1<br>
    foo2 b = propagate b foo2<br>
<br>
main = do<br>
<br>
let a = Bar1 3<br>
let b = Bar1 4<br>
let c = Exp1 (Exp2 a b) b<br>
<br>
print c<br>
print $ foo1 c<br>
print $ foo2 c<br>
----------------<br>
<br>
</div><div class="HOEnZb"><div class="h5">_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
</div></div></blockquote></div><br></div>