Closed cryogenian closed 8 years ago
That looks like a nice approach to me, I do worry about whether the typechecker is good enough to infer some of the constraint-heavy stuff without having to use a lot of explicit types. Have you tried mocking up any of this to see how it behaves?
No, I haven't. I'm going to make a sketch this night.
Probably it can be solved by phantom types, but I'm not sure.
Phantom types cannot be used in conjunction with do-notation.
What do you think about it?
Generally, I like the idea of encoding the charting library as a series of (Free) DSLs. This would play nicely with the new Halogen components and allow you to keep things purer for longer.
However, I do wonder how much time will be required for the project. Ultimately I think we need to build our own charting library, not based on echarts, which limits the amount of work we should spend on the echarts integration. That said, if it's not that much time, I think the benefits could be worth it.
:+1: for charting library.
I've made a sketch with newtypes wrapping Writer (List Command)
.
https://gist.github.com/cryogenian/7a3e874f4df67265bdad
I've made a sketch with newtypes wrapping Writer (List Command).
Looks nice and simple. Now the million dollar question: how long to implement this approach? :smile:
I think it will take 2-3 days to implement features that we currently use in slamdata, and maybe a 7-10 days to fully implement lib (I mean with tests, examples etc).
After spending some time on Writer
approach I found that it could be implementing with only one interpreter, and there is no need of typeclasses because we have rows in purescript :smile:
So, my current idea is
newtype Foo = Foo Foreign
for every complex type like tooltip, option or anythingForeign
s TooltipTrigger -> DSL (trigger ::I|i) Unit
This way there is no need to make something like ItemStyleable
, building option is much more convenient and composable, it has (in my opinion) the same levevl of type safety as records.
Drawbacks
itemStyle
to radar
, because one should look at RadarI
signature, not Radar
module ECharts.Monad where
import Prelude
import Control.Monad.Writer (Writer, execWriter)
import Control.Monad.Writer.Class (tell)
import Data.Array as Arr
import Data.Foreign (Foreign, toForeign)
import Data.Tuple (Tuple(..), uncurry)
import Data.Foldable as F
import ECharts.Types as T
import ECharts.Internal (unsafeSetField, emptyObject)
import Unsafe.Coerce (unsafeCoerce)
foreign import data I ∷ !
newtype DSL (i ∷ # !) a = DSL (Writer (Array (Tuple String Foreign)) a)
unDSL ∷ ∀ i a. DSL i a → Writer (Array (Tuple String Foreign)) a
unDSL (DSL cs) = cs
instance functorDSL ∷ Functor (DSL i) where
map f (DSL o) = DSL $ map f o
instance applyDSL ∷ Apply (DSL i) where
apply (DSL f) (DSL o) = DSL $ apply f o
instance applicativeDSL ∷ Applicative (DSL i) where
pure = DSL <<< pure
instance bindDSL ∷ Bind (DSL i) where
bind (DSL o) f = DSL $ o >>= unDSL <<< f
instance monadDSL ∷ Monad (DSL i)
set ∷ ∀ i. String → Foreign → DSL i Unit
set k v = DSL $ tell $ Arr.singleton $ Tuple k v
tooltipF ∷ ∀ i. T.Tooltip → DSL (tooltip ∷ I|i) Unit
tooltipF t = set "tooltip" $ T.unTooltip t
grid ∷ ∀ i. T.Grid → DSL (grid ∷ I|i) Unit
grid g = set "grid" $ T.unGrid g
boo ∷ ∀ i. Boolean → DSL (boo ∷ I|i) Unit
boo b = set "boo" $ toForeign b
shown ∷ ∀ i. Boolean → DSL (show ∷ I|i) Unit
shown b = set "show" $ toForeign b
shownContent ∷ ∀ i. Boolean → DSL (showContent ∷ I|i) Unit
shownContent b = set "showContent" $ toForeign b
trigger ∷ ∀ i. T.TooltipTrigger → DSL (trigger ∷ I|i) Unit
trigger t = set "trigger" $ toForeign $ T.printTooltipTrigger t
type TooltipI =
( show ∷ I
, showContent ∷ I
, trigger ∷ I
)
type OptionI =
( tooltip ∷ I
, grid ∷ I
, legend ∷ I
, xAxis ∷ I
, yAxis ∷ I
, color ∷ I
, series ∷ I
)
tooltip
∷ ∀ i
. DSL TooltipI Unit
→ DSL (tooltip ∷ I|i) Unit
tooltip = tooltipF <<< buildTooltip
buildTooltip
∷ DSL TooltipI Unit
→ T.Tooltip
buildTooltip (DSL cs) =
T.Tooltip $ F.foldr foldFn (emptyObject unit) $ execWriter cs
buildOption
∷ DSL OptionI Unit
→ T.Option
buildOption (DSL cs) =
T.Option $ F.foldr foldFn (emptyObject unit) $ execWriter cs
foldFn ∷ Tuple String Foreign → Foreign → Foreign
foldFn opt obj = uncurry (unsafeSetField obj) opt
tst ∷ T.Option
tst = buildOption do
tooltip do
shown false
grid $ unsafeCoerce unit
Is there a reason to invoke all the Writer
stuff other than syntactic ergonomics? You are effectively only using tell
, so why can't we just build the Array
ourselves? This is the same trick we do for the indexed HTML DSL in Halogen.
I think the only reason why I'd prefer Writer
here is that using something like
tooltip do
shown false
shown true
looks like sequence of action.
And here it looks like we create datatype instance that has two things inside.
tooltip
[ shown false
, shown true
]
see monad branch
Just [Just $ simpleDat 12, Just $ simpleDat 100500]
(a -> b) -> Json
in dynamic formatter and color.Here is my suggestion for
purescript-echarts
Option
,Serie
and other is to build them (seriesDefault {x = y}
)items :: forall f i o. (OptionLike o, Collection f, DataLike i) => f i -> o Unit
and provide instances of DataLike forNumber
,Int
etc.The only bad thing I see in interpreters that one can write
Probably it can be solved by phantom types, but I'm not sure.
What do you think about it?