3 -- import Numeric.Probability
4 import Control.Applicative (Applicative (..))
5 import Control.Monad (Monad (..), foldM_, forM_, mapM_, when, zipWithM_)
6 import Control.Monad.Trans.Class qualified as MT
7 import Control.Monad.Trans.Reader qualified as MT
8 import Control.Monad.Trans.Writer.CPS qualified as MT
9 import Data.Bool (otherwise, (&&))
10 import Data.ByteString.Builder qualified as BS
11 import Data.ByteString.Short qualified as BSh
12 import Data.Eq (Eq (..))
13 import Data.Foldable (foldMap', toList)
14 import Data.Function (id, on, ($), (&), (.))
15 import Data.Functor ((<&>))
17 import Data.List qualified as List
18 import Data.Map.Strict qualified as Map
19 import Data.Maybe (Maybe (..), fromMaybe)
20 import Data.Monoid (Monoid (..))
21 import Data.Ord (Ord (..))
22 import Data.Semigroup (Min (..), Semigroup (..))
24 import Data.Set qualified as Set
25 import Data.String (IsString (..), String)
26 import Data.Text.Lazy qualified as LazyText
27 import Data.Text.Lazy.Encoding qualified as LazyText
28 import Data.Text.Short (ShortText)
29 import Data.Text.Short qualified as ShortText
30 import Data.Tree qualified as Tree
31 import Debug.Pretty.Simple (pTraceShow)
32 import GHC.Real (floor)
33 import GHC.Stack (HasCallStack)
34 import Numeric (showFFloat)
35 import Text.Pretty.Simple (pShow)
36 import Text.Printf (printf)
37 import Text.Show (Show (..))
40 type DOT m = MT.ReaderT BSh.ShortByteString (MT.WriterT BS.Builder m) ()
42 indexFrom1M_ :: Applicative m => [a] -> (a -> Int -> m b) -> m ()
43 indexFrom1M_ xs f = zipWithM_ f xs [1 :: Int ..]
45 runDOT :: Monad m => DOT m -> m BS.Builder
46 runDOT = MT.execWriterT . (`MT.runReaderT` {-indent-} "")
48 dotBlock :: Monad m => DOT m -> DOT m
51 () <- MT.withReaderT (" " <>) s
54 dotLine :: Monad m => BS.Builder -> DOT m
57 MT.lift $ MT.tell $ BS.shortByteString indent <> s <> "\n"
59 dotComments :: Monad m => [BS.Builder] -> DOT m
65 dotEdges :: Monad m => [BS.Builder] -> [(BS.Builder, Value)] -> DOT m
66 dotEdges names as = dotLine $ mconcat (List.intersperse " -> " names) <> builderAttrs as
70 | ValueHTML BS.Builder
71 instance IsString Value where
72 fromString = ValueString
74 dotNode :: Monad m => BS.Builder -> [(BS.Builder, Value)] -> DOT m
75 dotNode name as = dotLine $ name <> builderAttrs as
77 builderAttrs :: [(BS.Builder, Value)] -> BS.Builder
80 | otherwise = "[" <> mconcat (List.intersperse "," attrs) <> "]"
85 , BS.toLazyByteString k /= ""
87 ValueString s -> s & builderQuotedString
88 ValueHTML s -> BS.charUtf8 '<' <> s <> BS.charUtf8 '>'
91 builderQuotedShortText :: ShortText -> BS.Builder
92 builderQuotedShortText = builderQuotedString . ShortText.unpack
94 builderQuotedString :: String -> BS.Builder
95 builderQuotedString cs = BS.charUtf8 '"' <> foldMap' escape cs <> BS.charUtf8 '"'
97 escape '\\' = BS.charUtf8 '\\' <> BS.charUtf8 '\\'
98 escape '\"' = BS.charUtf8 '\\' <> BS.charUtf8 '\"'
99 escape c = BS.charUtf8 c