module Repr
( Repr
, value
, renderer
, Renderer
, Precedence
, Fixity(..)
, render
, (<?>)
) where
import Data.String ( IsString, fromString )
import Data.String.ToString ( ToString, toString )
import Data.String.Combinators ( (<>)
, (<+>)
, between
, paren
, thenParen
, fromShow
, integer
, int
, hsep
)
import Data.DString ( DString, fromShowS )
import Control.Applicative ( liftA2 )
data Repr a = S { value :: a
, renderer :: Renderer
}
type Renderer = Precedence -> Fixity -> DString
type Precedence = Int
funAppPrec :: Precedence
funAppPrec = 10
data Fixity = Non
| L
| R
deriving Eq
render :: Repr a -> String
render r = toString $ renderer r 0 Non
(<?>) :: Repr a -> DString -> Repr a
(S x rx) <?> s =
S x $ \_ _ -> paren (between "{- " " -}" s <+> rx 0 Non)
instance Show (Repr a) where
show = render
instance Num a => Num (Repr a) where
fromInteger = from fromInteger "fromInteger"
(+) = infx L 6 (+) "+"
() = infx L 6 () "-"
(*) = infx L 7 (*) "*"
negate = app negate "negate"
abs = app abs "abs"
signum = app signum "signum"
instance Real a => Real (Repr a) where
toRational = to toRational
instance Integral a => Integral (Repr a) where
quot = app2 quot "quot"
rem = app2 rem "rem"
div = app2 div "div"
mod = app2 mod "mod"
quotRem = tup quotRem "quotRem"
divMod = tup divMod "divMod"
toInteger = to toInteger
instance Fractional a => Fractional (Repr a) where
(/) = infx L 7 (*) "/"
recip = app recip "recip"
fromRational = from fromRational "fromRational"
instance Floating a => Floating (Repr a) where
pi = constant pi "pi"
(**) = infx R 8 (**) "**"
logBase = app2 logBase "logBase"
exp = app exp "exp"
sqrt = app sqrt "sqrt"
log = app log "log"
sin = app sin "sin"
tan = app tan "tan"
cos = app cos "cos"
asin = app asin "asin"
atan = app atan "atan"
acos = app acos "acos"
sinh = app sinh "sinh"
tanh = app tanh "tanh"
cosh = app cosh "cosh"
asinh = app asinh "asinh"
atanh = app atanh "atanh"
acosh = app acosh "acosh"
instance RealFrac a => RealFrac (Repr a) where
properFraction (S x rx) =
let (n, f) = properFraction x
in (n, S f $ "snd" `apply` paren ("properFraction" <+> args [rx]))
instance RealFloat a => RealFloat (Repr a) where
floatRadix = to floatRadix
floatDigits = to floatDigits
floatRange = to floatRange
decodeFloat = to decodeFloat
encodeFloat = from2 encodeFloat "encodeFloat"
exponent = to exponent
significand = app significand "significand"
scaleFloat i = app (scaleFloat i) ("scaleFloat" <+> int i)
isNaN = to isNaN
isInfinite = to isInfinite
isDenormalized = to isDenormalized
isNegativeZero = to isNegativeZero
isIEEE = to isIEEE
atan2 = app2 atan2 "atan2"
instance Enum a => Enum (Repr a) where
succ = app succ "succ"
pred = app pred "pred"
toEnum = from toEnum "toEnum"
fromEnum = to fromEnum
enumFrom (S x rx) = enum "From" (enumFrom x) [rx]
enumFromThen (S x rx)
(S y ry) = enum "FromThen" (enumFromThen x y) [rx, ry]
enumFromTo (S x rx)
(S y ry) = enum "FromTo" (enumFromTo x y) [rx, ry]
enumFromThenTo (S x rx)
(S y ry)
(S z rz) = enum "FromThenTo" (enumFromThenTo x y z) [rx, ry, rz]
enum :: DString -> [a] -> [Renderer] -> [Repr a]
enum enumStr xs rxs = zipWith combine [0..] xs
where
combine i y = S y $ bin L 9 "!!" ("enum" <> enumStr <+> args rxs) (integer i)
instance Ord a => Ord (Repr a) where
compare = to2 compare
(<) = to2 (<)
(>=) = to2 (>=)
(>) = to2 (>)
(<=) = to2 (<=)
max = app2 max "max"
min = app2 min "min"
instance Eq a => Eq (Repr a) where
(==) = to2 (==)
(/=) = to2 (/=)
instance IsString a => IsString (Repr a) where
fromString = liftA2 constant fromString fromShow
constant :: a -> DString -> Repr a
constant x xStr = S x $ \_ _ -> xStr
from :: Show a => (a -> b) -> DString -> (a -> Repr b)
from f fStr =
\x -> S (f x) $ fStr `apply` fromShowS (showsPrec funAppPrec x)
from2 :: (Show a, Show b) => (a -> b -> c) -> DString -> (a -> b -> Repr c)
from2 f fStr =
\x y -> S (f x y) $ fStr `apply`( fromShowS (showsPrec funAppPrec x)
<+> fromShowS (showsPrec funAppPrec y)
)
to :: (a -> b) -> (Repr a -> b)
to f = f . value
to2 :: (a -> b -> c) -> (Repr a -> Repr b -> c)
to2 f = \x y -> f (value x) (value y)
app :: (a -> b) -> DString -> (Repr a -> Repr b)
app f fStr =
\(S x rx) -> S (f x) $ fStr `apply` args [rx]
app2 :: (a -> b -> c) -> DString -> (Repr a -> Repr b -> Repr c)
app2 f fStr =
\(S x rx) (S y ry) -> S (f x y) $ fStr `apply` args [rx, ry]
infx :: Fixity -> Precedence -> (a -> b -> c) -> DString
-> (Repr a -> Repr b -> Repr c)
infx opFix opPrec op opStr =
\(S x rx) (S y ry) ->
S (x `op` y) $ bin opFix opPrec opStr (rx opPrec L) (ry opPrec R)
bin :: Fixity -> Precedence -> DString -> DString -> DString -> Renderer
bin opFix opPrec opStr l r = \prec fixity -> (prec > opPrec ||
(prec == opPrec &&
fixity /= Non &&
fixity /= opFix))
`thenParen`
(l <+> opStr <+> r)
apply :: DString -> DString -> Renderer
funStr `apply` argsStr = \prec _ -> (prec >= funAppPrec)
`thenParen`
(funStr <+> argsStr)
args :: [Renderer] -> DString
args = hsep . map (\rx -> rx funAppPrec Non)
tup :: (a -> b -> (c, d)) -> DString
-> (Repr a -> Repr b -> (Repr c, Repr d))
tup f fStr =
\(S x rx) (S y ry) -> let (q, r) = f x y
s = paren (fStr <+> args [rx, ry])
in ( S q $ "fst" `apply` s
, S r $ "snd" `apply` s
)