我想使同一程序使用两个不同的Diagrams后端,尤其是diagrams-rasterific来生成PNG,并使用diagrams-svg来从同一图中生成SVG。由于图似乎是围绕使用单个后端设计的,因此我试图定义一个组合后端,但是在为Backend
实例定义renderToTree
时遇到麻烦:
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)
答案 0 :(得分:2)
我同意其他丹尼尔(Daniel)关于保持Diagram
多态并在两种类型中使用它的观点。像这样:
dia :: forall b. (Renderable (Path V2 Double) b, V b ~ V2, N b ~ Double) => Diagram b
dia = circle 1
当您添加基本类型时,类型信号只会变得更糟,因此我可能会为所有想要的基本类型定义一个约束:
type Back b = (V b ~ V2, N b ~ Double,
Renderable (Path V2 Double) b, Renderable (Text Double) b)
dia2 :: Back b => Diagram b
dia2 = circle 1 # fc blue
我认为我们无法为您的renderRTree
编写Multi
并进行类型检查。我们期望Renderable _ Multi
的 all 实例的格式为(Renderable p SVG, Renderable p Rasterific) => Renderable p Multi
,足以写成toA
。但是我们(AFAIK)无法向GHC承诺这一点,因为Renderable
是一个开放类型类。