module DBI where
import qualified Prelude as P
import Prelude (($), (.), (+), (), (++), show, (>>=), (*), (/), undefined)
import Util
import Data.Void
import Control.Monad (when)
import qualified Control.Monad.Writer as P
import qualified Data.Functor.Identity as P
import qualified Data.Tuple as P
class DBI repr where
z :: repr (a, h) a
s :: repr h b -> repr (a, h) b
lam :: repr (a, h) b -> repr h (a -> b)
app :: repr h (a -> b) -> repr h a -> repr h b
mkProd :: repr h (a -> b -> (a, b))
zro :: repr h ((a, b) -> a)
fst :: repr h ((a, b) -> b)
lit :: P.Double -> repr h P.Double
litZro :: repr h P.Double
litZro = lit 0
litOne :: repr h P.Double
litOne = lit 1
plus :: repr h (P.Double -> P.Double -> P.Double)
minus :: repr h (P.Double -> P.Double -> P.Double)
mult :: repr h (P.Double -> P.Double -> P.Double)
divide :: repr h (P.Double -> P.Double -> P.Double)
hoas :: (repr (a, h) a -> repr (a, h) b) -> repr h (a -> b)
hoas f = lam $ f z
fix :: repr h ((a -> a) -> a)
left :: repr h (a -> P.Either a b)
right :: repr h (b -> P.Either a b)
sumMatch :: repr h ((a -> c) -> (b -> c) -> P.Either a b -> c)
unit :: repr h ()
exfalso :: repr h (Void -> a)
nothing :: repr h (P.Maybe a)
just :: repr h (a -> P.Maybe a)
optionMatch :: repr h (b -> (a -> b) -> P.Maybe a -> b)
ioRet :: repr h (a -> P.IO a)
ioBind :: repr h (P.IO a -> (a -> P.IO b) -> P.IO b)
ioMap :: repr h ((a -> b) -> P.IO a -> P.IO b)
nil :: repr h [a]
cons :: repr h (a -> [a] -> [a])
listMatch :: repr h (b -> (a -> [a] -> b) -> [a] -> b)
com :: repr h ((b -> c) -> (a -> b) -> (a -> c))
com = hlam $ \f -> hlam $ \g -> hlam $ \x -> app f (app g x)
append :: repr h ([a] -> [a] -> [a])
append = hlam $ \l -> hlam $ \r -> fix2 (hlam $ \self -> listMatch2 r (hlam $ \a -> hlam $ \as -> cons2 a (app self as))) l
writer :: repr h ((a, w) -> P.Writer w a)
runWriter :: repr h (P.Writer w a -> (a, w))
swap :: repr h ((l, r) -> (r, l))
swap = hlam $ \p -> mkProd2 (fst1 p) (zro1 p)
flip :: repr h ((a -> b -> c) -> (b -> a -> c))
flip = hlam $ \f -> hlam $ \b -> hlam $ \a -> app2 f a b
id :: repr h (a -> a)
id = hlam $ \x -> x
const :: repr h (a -> b -> a)
const = hlam $ \x -> hlam $ \_ -> x
const1 = app const
cons2 = app2 cons
listMatch2 = app2 listMatch
fix2 = app2 fix
class DBI r => Monoid r m where
mzero :: r h m
mappend :: r h (m -> m -> m)
instance DBI r => Monoid r [a] where
mzero = nil
mappend = append
class DBI r => Functor r f where
map :: r h ((a -> b) -> (f a -> f b))
class Functor r a => Applicative r a where
pure :: r h (x -> a x)
ap :: r h (a (x -> y) -> a x -> a y)
return = pure
class Applicative r m => Monad r m where
bind :: r h (m a -> (a -> m b) -> m b)
join :: r h (m (m a) -> m a)
join = hlam $ \m -> bind2 m id
bind = hlam $ \m -> hlam $ \f -> join1 (app2 map f m)
bind2 = app2 bind
map1 = app map
join1 = app join
bimap2 = app2 bimap
flip1 = app flip
flip2 = app2 flip
class DBI r => BiFunctor r p where
bimap :: r h ((a -> b) -> (c -> d) -> p a c -> p b d)
instance DBI r => BiFunctor r (,) where
bimap = hlam $ \l -> hlam $ \r -> hlam $ \p -> mkProd2 (app l (zro1 p)) (app r (fst1 p))
instance DBI r => Functor r (P.Writer w) where
map = hlam $ \f -> com2 writer (com2 (bimap2 f id) runWriter)
writer1 = app writer
runWriter1 = app runWriter
mappend2 = app2 mappend
instance (DBI r, Monoid r w) => Applicative r (P.Writer w) where
pure = com2 writer (flip2 mkProd mzero)
ap = hlam $ \f -> hlam $ \x -> writer1 (mkProd2 (app (zro1 (runWriter1 f)) (zro1 (runWriter1 x))) (mappend2 (fst1 (runWriter1 f)) (fst1 (runWriter1 x))))
instance (DBI r, Monoid r w) => Monad r (P.Writer w) where
join = hlam $ \x -> writer1 $ mkProd2 (zro1 $ runWriter1 $ zro1 $ runWriter1 x) (mappend2 (fst1 $ runWriter1 $ zro1 $ runWriter1 x) (fst1 $ runWriter1 x))
instance DBI r => Functor r P.IO where
map = ioMap
ioBind2 = app2 ioBind
instance DBI r => Applicative r P.IO where
pure = ioRet
ap = hlam $ \f -> hlam $ \x -> ioBind2 f (flip2 ioMap x)
instance DBI r => Monad r P.IO where
bind = ioBind
app3 f x y z = app (app2 f x y) z
optionMatch3 = app3 optionMatch
optionMatch2 = app2 optionMatch
com2 = app2 com
instance DBI r => Functor r P.Maybe where
map = hlam $ \func -> optionMatch2 nothing (com2 just func)
instance DBI r => Applicative r P.Maybe where
pure = just
ap = optionMatch2 (const1 nothing) map
instance DBI r => Monad r P.Maybe where
bind = hlam $ \x -> hlam $ \func -> optionMatch3 nothing func x
newtype Eval h x = Eval {runEval :: h -> x}
comb = Eval . P.const
instance DBI Eval where
z = Eval P.fst
s (Eval a) = Eval $ a . P.snd
lam (Eval f) = Eval $ \a h -> f (h, a)
app (Eval f) (Eval x) = Eval $ \h -> f h $ x h
zro = comb P.fst
fst = comb P.snd
mkProd = comb (,)
lit = comb
plus = comb (+)
minus = comb ()
mult = comb (*)
divide = comb (/)
fix = comb loop
where loop x = x $ loop x
left = comb P.Left
right = comb P.Right
sumMatch = comb $ \l r -> \case
P.Left x -> l x
P.Right x -> r x
unit = comb ()
exfalso = comb absurd
nothing = comb P.Nothing
just = comb P.Just
ioRet = comb P.return
ioBind = comb (>>=)
nil = comb []
cons = comb (:)
listMatch = comb $ \l r -> \case
[] -> l
x:xs -> r x xs
optionMatch = comb $ \l r -> \case
P.Nothing -> l
P.Just x -> r x
ioMap = comb P.fmap
writer = comb (P.WriterT . P.Identity)
runWriter = comb P.runWriter
data AST = Leaf P.String | App P.String AST [AST] | Lam P.String [P.String] AST
appAST (Leaf f) x = App f x []
appAST (App f x l) r = App f x (l ++ [r])
appAST lam r = appAST (Leaf $ show lam) r
lamAST str (Lam s l t) = Lam str (s:l) t
lamAST str r = Lam str [] r
instance P.Show AST where
show (Leaf f) = f
show (App f x l) = "(" ++ f ++ " " ++ show x ++ P.concatMap ((" " ++) . show) l ++ ")"
show (Lam s l t) = "(\\" ++ s ++ P.concatMap (" " ++) l ++ " -> " ++ show t ++ ")"
newtype Show h a = Show {runShow :: [P.String] -> P.Int -> AST}
name = Show . P.const . P.const . Leaf
instance DBI Show where
z = Show $ P.const $ Leaf . show . P.flip () 1
s (Show v) = Show $ \vars -> v vars . P.flip () 1
lam (Show f) = Show $ \vars x -> lamAST (show x) (f vars (x + 1))
app (Show f) (Show x) = Show $ \vars h -> appAST (f vars h) (x vars h)
hoas f = Show $ \(v:vars) h ->
lamAST v (runShow (f $ Show $ P.const $ P.const $ Leaf v) vars h)
mkProd = name "mkProd"
zro = name "zro"
fst = name "fst"
lit x = name $ show x
plus = name "plus"
minus = name "minus"
mult = name "mult"
divide = name "divide"
fix = name "fix"
left = name "left"
right = name "right"
sumMatch = name "sumMatch"
unit = name "unit"
exfalso = name "exfalso"
nothing = name "nothing"
just = name "just"
ioRet = name "ioRet"
ioBind = name "ioBind"
nil = name "nil"
cons = name "cons"
listMatch = name "listMatch"
optionMatch = name "optionMatch"
ioMap = name "ioMap"
writer = name "writer"
runWriter = name "runWriter"
class NT repr l r where
conv :: repr l t -> repr r t
instance (DBI repr, NT repr l r) => NT repr l (a, r) where
conv = s . conv
instance NT repr x x where
conv = P.id
hlam :: forall repr a b h. DBI repr =>
((forall k. NT repr ((a, h)) k => repr k a) -> (repr (a, h)) b) -> repr h (a -> b)
hlam f = hoas (\x -> f $ conv x)
type family Diff x
type instance Diff P.Double = (P.Double, P.Double)
type instance Diff () = ()
type instance Diff (a, b) = (Diff a, Diff b)
type instance Diff (a -> b) = Diff a -> Diff b
type instance Diff (P.Either a b) = P.Either (Diff a) (Diff b)
type instance Diff Void = Void
type instance Diff (P.Maybe a) = P.Maybe (Diff a)
type instance Diff (P.IO a) = P.IO (Diff a)
type instance Diff [a] = [Diff a]
type instance Diff (P.Writer w a) = P.Writer (Diff w) (Diff a)
newtype WDiff repr h x = WDiff {runWDiff :: repr (Diff h) (Diff x)}
app2 f a = app (app f a)
mkProd1 = app mkProd
mkProd2 = app2 mkProd
plus2 = app2 plus
zro1 = app zro
fst1 = app fst
minus2 = app2 minus
mult2 = app2 mult
divide2 = app2 divide
instance DBI repr => DBI (WDiff repr) where
z = WDiff z
s (WDiff x) = WDiff $ s x
lam (WDiff f) = WDiff $ lam f
app (WDiff f) (WDiff x) = WDiff $ app f x
mkProd = WDiff mkProd
zro = WDiff zro
fst = WDiff fst
lit x = WDiff $ app (mkProd1 (lit x)) (lit 0)
plus = WDiff $ hlam $ \l -> hlam $ \r ->
mkProd2 (plus2 (zro1 l) (zro1 r)) (plus2 (fst1 l) (fst1 r))
minus = WDiff $ hlam $ \l -> hlam $ \r ->
mkProd2 (minus2 (zro1 l) (zro1 r)) (minus2 (fst1 l) (fst1 r))
mult = WDiff $ hlam $ \l -> hlam $ \r ->
mkProd2 (mult2 (zro1 l) (zro1 r))
(plus2 (mult2 (zro1 l) (fst1 r)) (mult2 (zro1 r) (fst1 l)))
divide = WDiff $ hlam $ \l -> hlam $ \r ->
mkProd2 (divide2 (zro1 l) (zro1 r))
(divide2 (minus2 (mult2 (zro1 r) (fst1 l)) (mult2 (zro1 l) (fst1 r)))
(mult2 (zro1 r) (zro1 r)))
hoas f = WDiff $ hoas (runWDiff . f . WDiff)
fix = WDiff fix
left = WDiff left
right = WDiff right
sumMatch = WDiff sumMatch
unit = WDiff unit
exfalso = WDiff exfalso
nothing = WDiff nothing
just = WDiff just
ioRet = WDiff ioRet
ioBind = WDiff ioBind
nil = WDiff nil
cons = WDiff cons
listMatch = WDiff listMatch
optionMatch = WDiff optionMatch
ioMap = WDiff ioMap
writer = WDiff writer
runWriter = WDiff runWriter
scomb = hlam $ \f -> hlam $ \x -> hlam $ \arg -> app (app f arg) (app x arg)
noEnv :: repr () x -> repr () x
noEnv = P.id