Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] is there an easier way to have "multi-main" with IO action support? #293

Open
Javran opened this issue Mar 17, 2017 · 7 comments

Comments

@Javran
Copy link

Javran commented Mar 17, 2017

Let's say we have the following code:

{-# LANGUAGE
    NoMonomorphismRestriction
  , FlexibleContexts
#-}
module Main where

import Diagrams.Prelude
import Diagrams.Backend.SVG.CmdLine

main :: IO ()
main = mainWith
    [ ("big", circle 10 :: Diagram B)
    , ("small", circle 1)
    ]

now suppose I want to have a circle of random size, or whatever action with IO involved.
while I could have performed all IO actions and still passing [(String, Diagram B)] to mainWith, but that's way too eager. so I turn the argument of mainWith to be [(String, IO (Diagram B))] (as the actual IO action does not really matter, I've omitted them to leave just pures):

main :: IO ()
main = mainWith
    [ ("big", pure $ circle 10 :: IO (Diagram B))
    , ("small", pure $ circle 1)
    ]

then GHC starts to complain about a missing instance of Mainable [(String, IO (Diagram B))].
this leads me to have to write the following stuff out in full (together with FlexibleInstances, TypeFamilies and probably -fno-warn-orphans):

instance SVGFloat n => Mainable [(String,IO (QDiagram SVG V2 n Any))] where
    type MainOpts [(String,IO (QDiagram SVG V2 n Any))]
        = (MainOpts (QDiagram SVG V2 n Any), DiagramMultiOpts)
    mainRender = defaultMultiMainRender

despite that there is a very close one in svg lib (i.e. Mainable [(String, Diagram B)]) but I really doubt GHC can figure this out by itself.

Is there anything to make this a bit easier, I don't really expect something that sounds easy to be this involved.

@byorgey
Copy link
Member

byorgey commented Mar 17, 2017

Good question. Actually, off the top of my head I see no reason we can't generalize the instance in diagrams-svg to something like

instance (SVGFloat n, Mainable d) => Mainable [(String, d)] where
  type MainOpts [(String, d)] = (MainOpts d, DiagramMultiOpts)
  mainRender = defaultMultiMainRender

We already have an instance Mainable d => Mainable (IO d) so this would cover your use case and a lot more besides. I'll try to look into doing this soon.

@cchalmers
Copy link
Member

You could write the generalised instance in Diagrams.Backend.CmdLine, you don't have to do it for each backend.

I've actually done this instance in my rewrite although the class is a little different there. I'll write a similar version for HEAD.

@cchalmers
Copy link
Member

Looking at the comment for defaultMultiMainRender it says:

We do not provide this instance in general so that backends can choose to opt-in to this form or provide a different instance that makes more sense.

But I feel like the instance generalises nicely. I can't think of any reason a backend would want a different instance. Is everyone happy with writing a instance Mainable d => Mainable [(String, d)] instance in Diagrams.Backend.CmdLine?

Note that writing that instance in diagrams-svg would overlap with any other backend that writes the same instance.

@fryguybob
Copy link
Member

I think I wrote that comment thinking about the [d] instance for multiple pages in postscript. It should be fine to have the general instance. Maybe a good general reasoning for this is all backends will be able to handle single diagrams so we should be able to have general instances for anything that has a straight forward interpretation (somewhat subjective) for running single diagrams. Backends that open up different interpretations (like postscript handling multiple pages or Rasterific handling animations) can use newtypes to have their specific interpretation of a general form.

@byorgey
Copy link
Member

byorgey commented Mar 17, 2017

Yes, sounds good to me. Let's put the general instance in Diagrams.Backend.CmdLine.

@byorgey
Copy link
Member

byorgey commented May 29, 2017

@cchalmers did we ever get around to this? If not, I can do it.

@cchalmers
Copy link
Member

@byorgey I remember looking at it but I must have forgot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants