basvandijk / scientific

Arbitrary-precision floating-point numbers represented using scientific notation
BSD 3-Clause "New" or "Revised" License
73 stars 40 forks source link

Internal module to expose constructor for Scientific #67

Open MaxGabriel opened 5 years ago

MaxGabriel commented 5 years ago

Hi, I have a newtype over Scientific and I've made a quasi quoter for using it in an expression. However, I believe to make a quasi quoter to use it in a pattern context I would need access to the constructor. Would you be open to adding an Internal module that exposes the constructor for Scientific?

For reference, this is how I create Scientifics in an expression context:

instance Lift Scientific where
  lift sci = 
    let coefficient = Scientific.coefficient sci
        base10Exponent = Scientific.base10Exponent sci
    in [|Scientific.scientific $(TH.lift coefficient) $(TH.lift base10Exponent)|]

-- | Arbitrary-precision value constrained to 0 through 100, inclusive.
newtype Percentage = Percentage Scientific
  deriving (Eq, Show, Read, Ord, ToJSON, Num, Fractional, Real, RealFrac, Lift)

mkPercentage :: Scientific -> Maybe Percentage
mkPercentage sci = if sci >= 0 && sci <= 100 then Just (Percentage sci) else Nothing

-- | Create a 'Percentage' at compile time
-- Usage:
-- > [compilePercentage|100|]
compilePercentage :: QuasiQuoter
compilePercentage = QuasiQuoter
    { quoteExp = quoteExp'
    , quotePat = error "percentage is not supported as a pattern" -- I don't think this can be implemented without access to the Scientific constructor. Maybe with the Num instance though?
    , quoteDec = error "percentage is not supported at top-level"
    , quoteType = error "percentage is not supported as a type"
    }
    where

    quoteExp' :: String -> Q Exp
    quoteExp' s = case (readMay s :: Maybe Scientific) >>= mkPercentage of
      Nothing -> fail $ "Invalid Percentage: " ++ s
      Just percentage -> [| percentage |]