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

New workflow again, Typesafe data source implementation #3

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

ahaym
Copy link
Member

@ahaym ahaym commented Aug 12, 2018

  • Remove |> and turn $> into the left-associative %>.

  • Massively increase type safety. A very large class of invalid BokeHS plots are now impossible to construct. In practice, this guarantees the validity of the Haskell AST at compile time (though perhaps errors can happen in serialization to JSON). Specifically, TypeLits are used to refer to columns so that their existence in the data source is guaranteed. The downside of this is the addition of typelevel boilerplate, though I try and keep this to a minimum.

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}

import Graphics.BokeHS
import qualified Data.ByteString.Lazy as BS
import Control.Monad
import System.Process
import Data.Scientific

myPlot :: Plot
myPlot = plt
    %> addLinearAxis BBelow
    %> addLinearAxis BLeft
    %> addLine myData2 (Key :: Key "x") (Key :: Key "y") def
        { lineColor = red
        , lineAlpha = 0.6
        , lineWidth = 6
        , lineCap = Rounded
        }
    %> addLine myData (Key :: Key "x") (Key :: Key "y2") def 
        { lineColor = green
        , lineDash = DotDash
        , lineWidth = 3
        }
    where plt = defaultPlot{
            width = 1000,
            height = 1000,
            title = "Sample BokeHS plot",
            xRange = Range1d (-0.5) 22,
            yRange = Range1d (-0.5) 22 
        }

main :: IO ()
main = do
    plotHTML <- emitPlotHTML myPlot
    BS.writeFile "sample.html" plotHTML
    void $ system "firefox --new-window sample.html"    

-- Automatic deriving for record types

data CustomData = CD
    { x :: Scientific
    , y :: Scientific }

myData2 :: [CustomData]

-- Or define your own: 

myData :: [(Scientific, Double)]

instance HasColumn (Scientific, Double) "x" Scientific where
    getValue _ (x, y) = x

instance HasColumn (Scientific, Double) "y2" Scientific where
    getValue _ (x, y) = fromFloatDigits y

To get around the lack of dependent types, we have to refer to columns as Key :: Key "Column". I can think of a few ways around this using type application or Template Haskell, though it doesn't seem too bad as is.

The more significant piece of boilerplate is the need of a HasColumn row name value | row name -> value instance, indicating that something of type value can be extracted from row type row, indexed by symbol name. Again, there are a variety of ways to remove the boilerplate here that I'm experimenting with. I include the simplest one, which is to automatically provide an overlappable instance for all record types using GHC.Records.HasField.

Makes missing column errors unrepresentable
Typesafe DataSource implementation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant