我想让同一个程序使用两个不同的Diagrams后端,特别是diagrams-rasterific从同一个图中生成 PNG,以及diagrams-svg生成 SVG。由于 Diagrams 似乎是围绕使用单个后端设计的,我试图定义一个组合后端,但在renderToTree
为Backend
实例定义时遇到了麻烦:
import Diagrams.Core
import Diagrams.Core.Types
import qualified Diagrams.Backend.Rasterific as BackendA
import qualified Diagrams.Backend.SVG as BackendB
tokenA :: BackendA.B
tokenA = BackendA.Rasterific
tokenB :: BackendB.B
tokenB = BackendB.SVG
data Multi = Multi
deriving (Eq, Ord, Read, Show)
type B = Multi
data MultiResult n = MultiResult (Result BackendA.B V2 n) (Result BackendB.B V2 n)
-- alternatively:
-- data MultiResult n =
-- ResultA (Result BackendA.B V2 n)
-- | ResultB (Result BackendB.B V2 n)
type instance V Multi = V2
type instance N Multi = Double
instance (TypeableFloat n, Show n) => Backend Multi V2 n where
data Render Multi V2 n =
RenderMulti
{ renderA :: Render BackendA.B V2 n
, renderB :: Render BackendB.B V2 n
}
-- alternatively:
-- data Render Multi V2 n =
-- RenderA (renderA :: Render BackendA.B V2 n)
-- | RenderB (renderB :: Render BackendB.B V2 n)
type Result Multi V2 n = MultiResult n
data Options Multi V2 n = MultiOptions
renderRTree _ o tree = MultiResult
(renderRTree tokenA (toOptA o) (treeToA tree))
(renderRTree tokenB (toOptB o) (treeToB tree))
我不清楚如何在renderRTree
这里遵循各个后端实现的功能。在任一替代结构中(将 Render 和 Result 类型作为总和或产品),我都无法使类型匹配。具体来说,在这种方法中,我被困在
treeToA :: RTree Multi V2 n a -> RTree BackendA.B V2 n a
treeToA = fmap f
where
f (RAnnot a) = RAnnot a
f (RStyle s) = RStyle s
f REmpty = REmpty
f (RPrim x) = RPrim (toA x)
toA :: Prim Multi V2 n -> Prim BackendA.B V2 n
toA = ???
但我不相信这甚至是要走的路。
toOptA
,toOptB
没问题,我可以在需要时填写。我也可以Renderable
使用任何一种方法为此后端提供实例,例如
instance (Show n, TypeableFloat n) => Renderable (Path V2 n) Multi where
render _ x = RenderMulti (render tokenA x) (render tokenB x)