module Debug.Reflect where
import Control.Applicative (Applicative(..), (<$>))
import Data.List (findIndex, isInfixOf, isPrefixOf)
import Data.Char (isAlpha)
infixr 5 ~>
data (~>) a b = Fn String (a -> b)
deriving (Functor)
fromFn :: (a ~> b) -> (a -> b)
fromFn (Fn _ f) = f
instance Show (a ~> b) where
show (Fn s _) = s
parens :: String -> String
parens s = "(" ++ s ++ ")"
isInfixFn :: String -> Bool
isInfixFn = not . any isAlpha
showFn :: String -> String -> String
showFn f x = if isInfixFn f then x ++ " " ++ f else f ++ " " ++ x
makeFn2 :: Show a => String -> (a -> b -> c) -> (a ~> b ~> c)
makeFn2 s f = Fn s $ \x -> Fn (showFn s (show x)) (f x)
makeBinOp :: Show a => String -> (a -> b -> c) -> (a ~> b ~> c)
makeBinOp s f = Fn s' $ \x -> Fn (parens $ showFn s (show x)) (f x)
where s' = if isInfixFn s then parens s else s
data Ap b
= Val b
| forall a. Show a => Ap (a ~> b) :$ Ap a
isVal :: Ap a -> Bool
isVal (Val _) = True
isVal _ = False
balanceParens :: String -> String
balanceParens s = if "<*>" `isInfixOf` s then parens s else s
parensFr :: String -> String
parensFr s = if ' ' `elem` s then parens s else s
showOp :: String -> String -> String -> String
showOp op f x
| isInfixFn op = f ++ " " ++ op ++ " " ++ balanceParens x
| otherwise = op ++ " " ++ f ++ " " ++ parensFr x
showF :: String -> String -> String
showF f x
| "fmap" `isPrefixOf` f = f ++ " " ++ parensFr x
| otherwise = f ++ " " ++ balanceParens x
instance Show a => Show (Ap a) where
show (Val x) = show x
show (op :$ f :$ x) = showOp (show op) (show f) (show x)
show (f :$ x) = showF (show f) (show x)
fmap' :: Functor f => (a ~> b) ~> f a ~> f b
fmap' = makeFn2 "<$>" (fmap . fromFn)
pure' :: Applicative f => a ~> f a
pure' = Fn "pure" pure
ap' :: (Show (f (a ~> b)), Applicative f) => f (a ~> b) ~> f a ~> f b
ap' = Fn "<*>" $ \f -> Fn (show f ++ " <*>") $ \x -> fromFn <$> f <*> x
infix 6 -$-
(-$-) :: (Show (f a), Functor f) => (a ~> b) -> f a -> Ap (f b)
f -$- x = Val fmap' :$ Val f :$ Val x
infixl 5 -*-
(-*-) :: (Show (f (a ~> b)), Show (f a), Applicative f) => Ap (f (a ~> b)) -> f a -> Ap (f b)
f -*- x = Val ap' :$ f :$ Val x
pure'' :: (Show a, Applicative f) => a -> Ap (f a)
pure'' x = Val pure' :$ Val x
fmap'' :: (Show (f a), Functor f) => (a ~> b) -> f a -> Ap (f b)
fmap'' f x = Val (makeFn2 "fmap" (fmap . fromFn)) :$ Val f :$ Val x
reduce'' :: Ap a -> Ap a
reduce'' (Val (Fn _ f) :$ Val x) = Val (f x)
reduce'' (Val f :$ x) = Val f :$ reduce'' x
reduce'' (f :$ x) = reduce'' f :$ x
reduce'' v = v
reduce' :: Show a => Ap a -> Ap a
reduce' x
| isVal x = x
| otherwise = head $ filter (\x' -> show x' /= show x) xs
where xs = iterate reduce'' x
reductions :: Show a => Ap a -> [Ap a]
reductions x = take (n + 1) xs
where
Just n = findIndex isVal xs
xs = iterate reduce' x