build: ghcid: run even with warnings
[haskell/symantic-parser.git] / src / Symantic / Parser / Grammar / Production.hs
index a0239aab1832eb53621cf710cdda9463b40d7dc7..d726884b006d4cd28892c729602bdc8710b10e02 100644 (file)
@@ -1,5 +1,4 @@
 {-# LANGUAGE DefaultSignatures #-}
-{-# LANGUAGE StandaloneDeriving #-} -- For prodCon
 {-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE StandaloneDeriving #-}
 {-# LANGUAGE DeriveLift #-}
@@ -8,11 +7,11 @@
 module Symantic.Parser.Grammar.Production where
 
 import Control.Monad (Monad(..))
-import Data.Functor.Identity (Identity(..))
-import Data.Functor.Product (Product(..))
-import Prelude (Num(..), undefined)
+--import Data.Functor.Product (Product(..))
+import Prelude (Num(..), undefined, error)
 import Text.Show (Show(..), showString)
 import Type.Reflection (Typeable)
+import qualified Control.Applicative as App
 import qualified Data.Either as Either
 import qualified Data.Eq as Eq
 import qualified Data.Function as Fun
@@ -20,38 +19,76 @@ import qualified Data.Maybe as Maybe
 import qualified Language.Haskell.TH as TH
 import qualified Language.Haskell.TH.Syntax as TH
 import qualified Language.Haskell.TH.Show as TH
+import Data.Kind (Type)
 
-import Symantic.Data
-import Symantic.Lang
-import Symantic.Derive
+import Symantic.Syntaxes.Classes
+import Symantic.Semantics.Data
+import Symantic.Semantics.Identity
+import Symantic.Syntaxes.Derive
 
-type Production = Product
-  (SomeData Identity)
-  (SomeData TH.CodeQ)
+data Production (vs :: [Type]) a where
+  -- TODO: move SomeData from Prod to here?
+  ProdE :: Prod a -> Production vs a
+  --ProdV :: Production (a ': vs) a
+  --ProdN :: Production vs (a->b) -> Production (a ': vs) b
+  --ProdW :: Production vs b -> Production (a ': vs) b
+
+data Prod a = Prod
+  { prodI :: SomeData Identity a
+  , prodQ :: SomeData TH.CodeQ a
+  }
+
+appProd ::
+  Production vs (a -> b) ->
+  Production vs a ->
+  Production vs b
+--ProdE p `appProd` ProdN e = ProdN (ProdE ((.) .@ p) `appProd` e)
+--ProdE p `appProd` ProdV = ProdN (ProdE p)
+--ProdE p `appProd` ProdW e = ProdW (ProdE p `appProd` e)
+ProdE p1 `appProd` ProdE p2 = ProdE (p1 .@ p2)
+--ProdN e `appProd` ProdE p = ProdN (ProdE (flip .@ flip .@ p) `appProd` e)
+--ProdN e `appProd` ProdV = ProdN (ProdE ap `appProd` e `appProd` ProdE id)
+--ProdN e1 `appProd` ProdN e2 = ProdN (ProdE ap `appProd` e1 `appProd` e2)
+--ProdN e1 `appProd` ProdW e2 = ProdN (ProdE flip `appProd` e1 `appProd` e2)
+--ProdV `appProd` ProdE p = ProdN (ProdE (flip .@ id .@ p))
+--ProdV `appProd` ProdN e = ProdN (ProdE (ap .@ id) `appProd` e)
+--ProdV `appProd` ProdW e = ProdN (ProdE (flip .@ id) `appProd` e)
+--ProdW e `appProd` ProdE p = ProdW (e `appProd` ProdE p)
+--ProdW e `appProd` ProdV = ProdN e
+--ProdW e1 `appProd` ProdN e2 = ProdN (ProdE (.) `appProd` e1 `appProd` e2)
+--ProdW e1 `appProd` ProdW e2 = ProdW (e1 `appProd` e2)
+
+-- data Production a where
+--   Prod :: { prodI :: SomeData Identity a
+--           , prodQ :: SomeData TH.CodeQ a
+--           } -> Production a
+--   ProdV :: Production a
+--   ProdN :: Production a -> Production a
+--   ProdW :: Production a -> Production a
 
 {-# INLINE prodValue #-}
-prodValue :: Production a -> SomeData Identity a
-prodValue (Pair v _) = v
+prodValue :: Production '[] a -> SomeData Identity a
+prodValue (ProdE (Prod v _)) = v
 {-# INLINE prodCode #-}
-prodCode :: Production a -> SomeData TH.CodeQ a
-prodCode (Pair _ c) = c
+prodCode :: Production '[] a -> SomeData TH.CodeQ a
+prodCode (ProdE (Prod _ c)) = c
 
 {-# INLINE production #-}
-production :: a -> TH.CodeQ a -> Production a
-production v c = Pair
+production :: a -> TH.CodeQ a -> Production vs a
+production v c = ProdE (Prod
   (SomeData (Var (Identity v)))
-  (SomeData (Var c))
+  (SomeData (Var c)))
 
 {-# INLINE prod #-}
-prod :: TH.Lift a => a -> Production a
+prod :: TH.Lift a => a -> Production vs a
 prod x = production x [||x||]
 
 {-# INLINE runValue #-}
-runValue :: Production a -> a
-runValue (Pair v _c) = runIdentity (derive v)
+runValue :: Production '[] a -> a
+runValue (ProdE (Prod v _c)) = runIdentity (derive v)
 {-# INLINE runCode #-}
-runCode :: Production a -> TH.CodeQ a
-runCode (Pair _v c) = derive c
+runCode :: Production '[] a -> TH.CodeQ a
+runCode (ProdE (Prod _v c)) = derive c
 
 -- Missing instances in 'Language.Haskell.TH',
 -- needed for 'prodCon'.
@@ -70,6 +107,7 @@ prodCon name = do
     TH.DataConI n _ty _pn ->
       [| production $(return (TH.ConE n))
            (TH.unsafeCodeCoerce (return (TH.ConE $(TH.lift n)))) |]
+    _ -> error "[BUG]: impossible prodCon case"
 
 instance Show (SomeData TH.CodeQ a) where
   -- The 'Derivable' constraint contained in 'SomeData'
@@ -77,92 +115,111 @@ instance Show (SomeData TH.CodeQ a) where
   -- Fortunately 'TH.showCode' can be implemented.
   showsPrec p = showString Fun.. TH.showCode p Fun.. derive
 
-instance (Abstractable f, Abstractable g) => Abstractable (Product f g) where
+unProdE :: Production '[] a -> Prod a
+unProdE t = case t of ProdE t' -> t'
+
+instance Abstractable (Production '[]) where
+  lam f = ProdE (lam (unProdE Fun.. f Fun.. ProdE))
+instance Abstractable1 (Production '[]) where
+  lam1 f = ProdE (lam1 (unProdE Fun.. f Fun.. ProdE))
+instance Abstractable Prod where
   -- Those 'undefined' are not unreachables by 'f'
   -- but this is the cost to pay for defining this instance.
   -- In particular, 'f' must not define the 'TH.CodeQ' part
   -- using the 'Identity' part.
-  lam f = Pair
-    (lam (\x -> let Pair fx _ = f (Pair x undefined) in fx))
-    (lam (\y -> let Pair _ fy = f (Pair undefined y) in fy))
-  lam1 f = Pair
-    (lam1 (\x -> let Pair fx _ = f (Pair x undefined) in fx))
-    (lam1 (\y -> let Pair _ fy = f (Pair undefined y) in fy))
-  const = Pair const const
-  var = Fun.id
-  id = Pair id id
-  flip = Pair flip flip
-  Pair f1 f2 .@ Pair x1 x2 = Pair (f1 .@x1) (f2 .@x2)
-  (.) = Pair (.) (.)
-  ($) = Pair ($) ($)
-instance (Num (f a), Num (g a)) => Num (Product f g a) where
-  Pair x1 x2 + Pair y1 y2 = Pair (x1 + y1) (x2 + y2)
-  Pair x1 x2 * Pair y1 y2 = Pair (x1 * y1) (x2 * y2)
-  Pair x1 x2 - Pair y1 y2 = Pair (x1 - y1) (x2 - y2)
-  abs (Pair x1 x2) = Pair (abs x1) (abs x2)
-  fromInteger i = Pair (fromInteger i) (fromInteger i)
-  negate (Pair x1 x2) = Pair (negate x1) (negate x2)
-  signum (Pair x1 x2) = Pair (signum x1) (signum x2)
-instance (Eitherable f, Eitherable g) => Eitherable (Product f g) where
-  left = Pair left left
-  right = Pair right right
-instance (TH.Lift c, Typeable c) => Constantable c Production where
-  constant c = Pair (constant c) (constant c)
-instance Maybeable Production where
-  nothing = Pair nothing nothing
-  just = Pair just just
-instance Listable Production where
-  nil = Pair nil nil
-  cons = Pair cons cons
-instance Equalable Production where
-  equal = Pair equal equal
-
--- Identity
-instance Anythingable Identity
-instance Abstractable Identity where
-  f .@ x = Identity (runIdentity f (runIdentity x))
-  lam f = Identity (runIdentity Fun.. f Fun.. Identity)
-  lam1 = lam
+  lam f = Prod
+    (lam (\x -> let Prod fx _ = f (Prod x undefined) in fx))
+    (lam (\y -> let Prod _ fy = f (Prod undefined y) in fy))
+instance Abstractable1 Prod where
+  lam1 f = Prod
+    (lam1 (\x -> let Prod fx _ = f (Prod x undefined) in fx))
+    (lam1 (\y -> let Prod _ fy = f (Prod undefined y) in fy))
+instance Instantiable (Production vs) where
+  (.@) = appProd
+instance Instantiable Prod where
+  Prod f1 f2 .@ Prod x1 x2 = Prod (f1 .@ x1) (f2 .@ x2)
+instance Varable Prod where
   var = Fun.id
-  const = Identity Fun.const
-  flip = Identity Fun.flip
-  id = Identity Fun.id
-  ($) = Identity (Fun.$)
-  (.) = Identity (Fun..)
-instance Constantable c Identity where
-  constant = Identity
-instance Eitherable Identity where
-  left = Identity Either.Left
-  right = Identity Either.Right
-instance Equalable Identity where
-  equal = Identity (Eq.==)
-instance IfThenElseable Identity where
-  ifThenElse test ok ko = Identity
-    (if runIdentity test
-    then runIdentity ok
-    else runIdentity ko)
-instance Listable Identity where
-  cons = Identity (:)
-  nil = Identity []
-instance Maybeable Identity where
-  nothing = Identity Maybe.Nothing
-  just = Identity Maybe.Just
+instance Unabstractable (Production vs) where
+  ap = ProdE ap
+  const = ProdE const
+  id = ProdE id
+  (.) = ProdE (.)
+  flip = ProdE flip
+  ($) = ProdE ($)
+instance Unabstractable Prod where
+  ap = Prod ap ap
+  const = Prod const const
+  id = Prod id id
+  flip = Prod flip flip
+  (.) = Prod (.) (.)
+  ($) = Prod ($) ($)
+instance (Num (SomeData Identity a), Num (SomeData TH.CodeQ a)) => Num (Prod a) where
+  Prod x1 x2 + Prod y1 y2 = Prod (x1 + y1) (x2 + y2)
+  Prod x1 x2 * Prod y1 y2 = Prod (x1 * y1) (x2 * y2)
+  Prod x1 x2 - Prod y1 y2 = Prod (x1 - y1) (x2 - y2)
+  abs (Prod x1 x2) = Prod (abs x1) (abs x2)
+  fromInteger i = Prod (fromInteger i) (fromInteger i)
+  negate (Prod x1 x2) = Prod (negate x1) (negate x2)
+  signum (Prod x1 x2) = Prod (signum x1) (signum x2)
+instance Eitherable (Production vs) where
+  either = ProdE either
+  left = ProdE left
+  right = ProdE right
+instance Eitherable Prod where
+  either = Prod either either
+  left = Prod left left
+  right = Prod right right
+instance (TH.Lift c, Typeable c) => Constantable c (Production vs) where
+  constant c = ProdE (constant c)
+instance (TH.Lift c, Typeable c) => Constantable c Prod where
+  constant c = Prod (constant c) (constant c)
+instance (Inferable a (SomeData Identity), Inferable a (SomeData TH.CodeQ)) => Inferable a (Production vs) where
+  infer = ProdE infer
+instance (Inferable a (SomeData Identity), Inferable a (SomeData TH.CodeQ)) => Inferable a Prod where
+  infer = Prod infer infer
+instance Maybeable (Production vs) where
+  nothing = ProdE nothing
+  just = ProdE just
+instance Maybeable Prod where
+  nothing = Prod nothing nothing
+  just = Prod just just
+instance Listable (Production vs) where
+  nil = ProdE nil
+  cons = ProdE cons
+instance Listable Prod where
+  nil = Prod nil nil
+  cons = Prod cons cons
+instance Equalable (Production vs) where
+  equal = ProdE equal
+instance Equalable Prod where
+  equal = Prod equal equal
+instance Inferable () (SomeData Identity) where
+  infer = constant ()
+instance Inferable () (SomeData TH.CodeQ) where
+  infer = constant ()
 
 -- TH.CodeQ
 instance Anythingable TH.CodeQ
 instance Abstractable TH.CodeQ where
-  (.@) f x = [|| $$f $$x ||]
   lam f = [|| \x -> $$(f [||x||]) ||]
-  lam1 = lam
+instance Instantiable TH.CodeQ where
+  f .@ x = [|| $$f $$x ||]
+instance Abstractable1 TH.CodeQ where
+  lam1 f = [|| \u -> $$(f [||u||]) ||]
+instance Varable TH.CodeQ where
   var = Fun.id
-  id = [|| \x -> x ||]
+instance Unabstractable TH.CodeQ where
+  ap = [|| (App.<*>) ||]
+  id = [|| Fun.id ||]
   const = [|| Fun.const ||]
-  flip = [|| \f x y -> f y x ||]
+  flip = [|| Fun.flip ||]
   ($) = [|| (Fun.$) ||]
   (.) = [|| (Fun..) ||]
 instance TH.Lift c => Constantable c TH.CodeQ where
   constant c = [|| c ||]
 instance Eitherable TH.CodeQ where
+  either = [|| Either.either ||]
   left = [|| Either.Left ||]
   right = [|| Either.Right ||]
 instance Equalable TH.CodeQ where