| 211 | ==== SYB3 ==== |
| 212 | |
| 213 | The SYB3 approach faces similar challenges when it comes |
| 214 | to modularity. |
| 215 | |
| 216 | The generic cases. |
| 217 | {{{ |
| 218 | class Typable a => Data a where |
| 219 | gmapQ :: (forall b. Data b => b -> r) -> a -> [r] |
| 220 | |
| 221 | instance Data Char where |
| 222 | gmapQ f c = [] |
| 223 | instance Data a => Data [a] where |
| 224 | gmapQ f (x:xs) = [f x, f xs] |
| 225 | }}} |
| 226 | |
| 227 | A new generic "size" function. |
| 228 | {{{ |
| 229 | class Size a where |
| 230 | gsize :: a -> Int |
| 231 | -- specific instance |
| 232 | instance Size Name where ... |
| 233 | -- generic instance, |
| 234 | -- we use overlapping instances to cover all remaining cases |
| 235 | instance Data t => Size t where -- (S) |
| 236 | gsize t = 1 + sum (gmapQ gsize t) |
| 237 | }}} |
| 238 | The problem is that the instance (S) will not type check. |
| 239 | The program text gmapQ size is the trouble maker. |
| 240 | In this specific context, the combinator gmapQ expects as |
| 241 | its first argument a function of type |
| 242 | {{{ |
| 243 | forall a. Data a => a -> Int |
| 244 | }}} |
| 245 | and the actual argument gsize has type |
| 246 | {{{ |
| 247 | forall a. Size a => a -> Int |
| 248 | }}} |
| 249 | But the second type is not a subtype of the second. |
| 250 | For this subtype relation to hold, if we can satisfy |
| 251 | the condition |
| 252 | that from 'Data a' we can derive 'Size a' for any 'a'. |
| 253 | This condition is satisfied |
| 254 | if we make 'Sizes' a superclass of 'Data'. |
| 255 | But this will break modularity (we have to change |
| 256 | 'Data's class declaration for each new generic function). |
| 257 | |
| 258 | '''MS note''': How to fix the (modularity) problem via indexed classes? |
| 259 | |