RSolve 0.1.0.1 → 2.0.0.0
raw patch · 15 files changed
+682/−531 lines, 15 filesdep +RSolvedep +lensdep +mtldep ~basenew-component:exe:RSolve-exePVP ok
version bump matches the API change (PVP)
Dependencies added: RSolve, lens, mtl
Dependency ranges changed: base
API changes (from Hackage documentation)
- RSolve.BrMonad: Br :: (s -> [(a, s)]) -> Br s a
- RSolve.BrMonad: [runBr] :: Br s a -> s -> [(a, s)]
- RSolve.BrMonad: getBy :: () => (t -> a) -> Br t a
- RSolve.BrMonad: instance Control.Monad.Fail.MonadFail (RSolve.BrMonad.Br s)
- RSolve.BrMonad: instance GHC.Base.Alternative (RSolve.BrMonad.Br s)
- RSolve.BrMonad: instance GHC.Base.Applicative (RSolve.BrMonad.Br s)
- RSolve.BrMonad: instance GHC.Base.Functor (RSolve.BrMonad.Br s)
- RSolve.BrMonad: instance GHC.Base.Monad (RSolve.BrMonad.Br s)
- RSolve.BrMonad: newtype Br s a
- RSolve.BrMonad: putBy :: () => (t -> t) -> Br t ()
- RSolve.HM.Core: Arrow :: TypeOp
- RSolve.HM.Core: Char :: Prim
- RSolve.HM.Core: Float :: Prim
- RSolve.HM.Core: Int :: Prim
- RSolve.HM.Core: Join :: TypeOp
- RSolve.HM.Core: Stmt :: TypeOp
- RSolve.HM.Core: [Forall] :: [Id] -> Core -> Core
- RSolve.HM.Core: [Op] :: TypeOp -> Core -> Core -> Core
- RSolve.HM.Core: [Prim] :: Prim -> Core
- RSolve.HM.Core: [Var] :: Id -> Core
- RSolve.HM.Core: data Core
- RSolve.HM.Core: data Prim
- RSolve.HM.Core: data TypeOp
- RSolve.HM.Core: free :: Map Id Core -> Core -> Core
- RSolve.HM.Core: instance GHC.Classes.Eq RSolve.HM.Core.Core
- RSolve.HM.Core: instance GHC.Classes.Eq RSolve.HM.Core.Prim
- RSolve.HM.Core: instance GHC.Classes.Eq RSolve.HM.Core.TypeOp
- RSolve.HM.Core: instance GHC.Classes.Ord RSolve.HM.Core.Prim
- RSolve.HM.Core: instance GHC.Classes.Ord RSolve.HM.Core.TypeOp
- RSolve.HM.Core: instance GHC.Show.Show RSolve.HM.Core.Core
- RSolve.HM.Core: instance GHC.Show.Show RSolve.HM.Core.Prim
- RSolve.HM.Core: instance GHC.Show.Show RSolve.HM.Core.TypeOp
- RSolve.HM.Core: instance RSolve.Infr.Reference RSolve.HM.Core.Core
- RSolve.HM.Core: instance RSolve.Infr.Unify RSolve.HM.Core.Core
- RSolve.HM.Core: occurIn :: Addr -> Addr -> Br (LState Core) Bool
- RSolve.HM.Core: type Id = Int
- RSolve.Infr: Allocator :: Map Addr a -> Addr -> Allocator a
- RSolve.Infr: LState :: Allocator a -> [(a, a)] -> [Br (LState a) Bool] -> LState a
- RSolve.Infr: [addr] :: Allocator a -> Addr
- RSolve.Infr: [allocator] :: LState a -> Allocator a
- RSolve.Infr: [constrains] :: LState a -> [Br (LState a) Bool]
- RSolve.Infr: [negPairs] :: LState a -> [(a, a)]
- RSolve.Infr: [storage] :: Allocator a -> Map Addr a
- RSolve.Infr: alloc :: Reference a => a -> Allocator a -> (Addr, Allocator a)
- RSolve.Infr: allocator' :: () => Allocator a -> LState a -> LState a
- RSolve.Infr: class EnumSet a
- RSolve.Infr: class Eq a => Reference a
- RSolve.Infr: class Reference a => Unify a
- RSolve.Infr: complement :: Unify a => a -> a -> Br (LState a) ()
- RSolve.Infr: constrains' :: () => [Br (LState a) Bool] -> LState a -> LState a
- RSolve.Infr: data Allocator a
- RSolve.Infr: data LState a
- RSolve.Infr: emptyAllocator :: () => Allocator a
- RSolve.Infr: emptyLState :: () => LState a
- RSolve.Infr: inc :: Reference a => Allocator a -> (Addr, Allocator a)
- RSolve.Infr: instance GHC.Show.Show a => GHC.Show.Show (RSolve.Infr.Allocator a)
- RSolve.Infr: isRef :: Reference a => a -> Maybe Addr
- RSolve.Infr: load :: Addr -> Br (LState a) a
- RSolve.Infr: mkRef :: Reference a => Addr -> a
- RSolve.Infr: negPairs' :: () => [(a, a)] -> LState a -> LState a
- RSolve.Infr: negUnify :: Reference a => a -> a -> Br (LState a) ()
- RSolve.Infr: new :: Reference a => Br (LState a) Addr
- RSolve.Infr: prune :: Unify a => a -> Br (LState a) a
- RSolve.Infr: renew :: Reference a => Addr -> a -> Allocator a -> Allocator a
- RSolve.Infr: store :: (Reference a, Eq a) => a -> Br (LState a) a
- RSolve.Infr: toEnumerable :: EnumSet a => Br (LState a) ()
- RSolve.Infr: tryLoad :: Addr -> Br (LState a) (Maybe a)
- RSolve.Infr: type Addr = Int
- RSolve.Infr: unify :: Unify a => a -> a -> Br (LState a) ()
- RSolve.Infr: update :: Reference a => Addr -> a -> Br (LState a) ()
- RSolve.Logic: [And] :: Cond a -> Cond a -> Cond a
- RSolve.Logic: [Imply] :: Cond a -> Cond a -> Cond a
- RSolve.Logic: [Not] :: Cond a -> Cond a
- RSolve.Logic: [Or] :: Cond a -> Cond a -> Cond a
- RSolve.Logic: [Pred] :: Br (LState a) Bool -> Cond a
- RSolve.Logic: [Unify] :: Unify a => a -> a -> Cond a
- RSolve.Logic: data Cond a
- RSolve.Logic: require :: Unify a => a -> Br (LState a) a
- RSolve.Logic: solve :: Cond a -> Br (LState a) ()
- RSolve.Logic: solveNeg :: Unify a => Br (LState a) ()
- RSolve.Logic: solvePred :: EnumSet a => Br (LState a) ()
- RSolve.Options.Core: A :: Option
- RSolve.Options.Core: B :: Option
- RSolve.Options.Core: C :: Option
- RSolve.Options.Core: D :: Option
- RSolve.Options.Core: Sol :: Set Option -> Term
- RSolve.Options.Core: Var :: Int -> Term
- RSolve.Options.Core: data Option
- RSolve.Options.Core: data Term
- RSolve.Options.Core: instance GHC.Classes.Eq RSolve.Options.Core.Option
- RSolve.Options.Core: instance GHC.Classes.Eq RSolve.Options.Core.Term
- RSolve.Options.Core: instance GHC.Classes.Ord RSolve.Options.Core.Option
- RSolve.Options.Core: instance GHC.Enum.Enum RSolve.Options.Core.Option
- RSolve.Options.Core: instance GHC.Show.Show RSolve.Options.Core.Option
- RSolve.Options.Core: instance GHC.Show.Show RSolve.Options.Core.Term
- RSolve.Options.Core: instance RSolve.Infr.EnumSet RSolve.Options.Core.Term
- RSolve.Options.Core: instance RSolve.Infr.Reference RSolve.Options.Core.Term
- RSolve.Options.Core: instance RSolve.Infr.Unify RSolve.Options.Core.Term
- RSolve.Options.Core: pruneSol :: Term -> Br (LState Term) (Int, Maybe (Set Option))
+ RSolve.HM: (:*) :: T -> T -> T
+ RSolve.HM: (:->) :: T -> T -> T
+ RSolve.HM: TApp :: T -> T -> T
+ RSolve.HM: TCEnv :: Map Int T -> Map Int T -> Set (T, T) -> TCEnv
+ RSolve.HM: TForall :: Set String -> T -> T
+ RSolve.HM: TFresh :: String -> T
+ RSolve.HM: TNom :: Int -> T
+ RSolve.HM: TVar :: Int -> T
+ RSolve.HM: Unif :: T -> T -> Bool -> Unif
+ RSolve.HM: [_neqs] :: TCEnv -> Set (T, T)
+ RSolve.HM: [_noms] :: TCEnv -> Map Int T
+ RSolve.HM: [_tvars] :: TCEnv -> Map Int T
+ RSolve.HM: [lhs] :: Unif -> T
+ RSolve.HM: [neq] :: Unif -> Bool
+ RSolve.HM: [rhs] :: Unif -> T
+ RSolve.HM: addNEq :: (T, T) -> MS TCEnv ()
+ RSolve.HM: data T
+ RSolve.HM: data TCEnv
+ RSolve.HM: data Unif
+ RSolve.HM: deConsTOp :: T -> Maybe (T -> T -> T, T, T)
+ RSolve.HM: emptyTCEnv :: TCEnv
+ RSolve.HM: free :: Map String T -> T -> T
+ RSolve.HM: infixl 6 :->
+ RSolve.HM: instance GHC.Classes.Eq RSolve.HM.T
+ RSolve.HM: instance GHC.Classes.Eq RSolve.HM.Unif
+ RSolve.HM: instance GHC.Classes.Ord RSolve.HM.T
+ RSolve.HM: instance GHC.Classes.Ord RSolve.HM.Unif
+ RSolve.HM: instance GHC.Show.Show RSolve.HM.T
+ RSolve.HM: instance GHC.Show.Show RSolve.HM.TCEnv
+ RSolve.HM: instance GHC.Show.Show RSolve.HM.Unif
+ RSolve.HM: instance RSolve.Logic.AtomF RSolve.HM.Unif
+ RSolve.HM: instance RSolve.Solver.CtxSolver RSolve.HM.TCEnv RSolve.HM.Unif
+ RSolve.HM: loadTVar :: Int -> MS TCEnv T
+ RSolve.HM: neqs :: Lens' TCEnv (Set (T, T))
+ RSolve.HM: newTNom :: MS TCEnv Int
+ RSolve.HM: newTVar :: MS TCEnv Int
+ RSolve.HM: noms :: Lens' TCEnv (Map Int T)
+ RSolve.HM: occurIn :: Int -> T -> MS TCEnv Bool
+ RSolve.HM: prune :: T -> MS TCEnv T
+ RSolve.HM: tvars :: Lens' TCEnv (Map Int T)
+ RSolve.HM: type Fix a = a -> a
+ RSolve.HM: unify :: Fix (Unif -> MS TCEnv ())
+ RSolve.HM: update :: Int -> T -> MS TCEnv ()
+ RSolve.Logic: class (Show a, Ord a) => AtomF a
+ RSolve.Logic: notA :: AtomF a => a -> [a]
+ RSolve.MapLike: (!) :: MapLike m k v => m -> k -> v
+ RSolve.MapLike: adjust :: MapLike m k v => (v -> v) -> k -> m -> m
+ RSolve.MapLike: class MapLike m k v | m -> k, m -> v
+ RSolve.MapLike: insert :: MapLike m k v => k -> v -> m -> m
+ RSolve.MapLike: instance GHC.Classes.Eq k => RSolve.MapLike.MapLike [(k, v)] k v
+ RSolve.MapLike: instance GHC.Classes.Ord k => RSolve.MapLike.MapLike (Data.Map.Internal.Map k v) k v
+ RSolve.MapLike: lookup :: MapLike m k v => k -> m -> Maybe v
+ RSolve.MapLike: member :: MapLike m k v => k -> m -> Bool
+ RSolve.MapLike: update :: MapLike m k v => (v -> Maybe v) -> k -> m -> m
+ RSolve.MultiState: MS :: (s -> [(a, s)]) -> MS s a
+ RSolve.MultiState: [runMS] :: MS s a -> s -> [(a, s)]
+ RSolve.MultiState: getMS :: MS s s
+ RSolve.MultiState: getsMS :: (s -> a) -> MS s a
+ RSolve.MultiState: instance Control.Monad.Fail.MonadFail (RSolve.MultiState.MS s)
+ RSolve.MultiState: instance GHC.Base.Alternative (RSolve.MultiState.MS s)
+ RSolve.MultiState: instance GHC.Base.Applicative (RSolve.MultiState.MS s)
+ RSolve.MultiState: instance GHC.Base.Functor (RSolve.MultiState.MS s)
+ RSolve.MultiState: instance GHC.Base.Monad (RSolve.MultiState.MS s)
+ RSolve.MultiState: modifyMS :: (s -> s) -> MS s ()
+ RSolve.MultiState: newtype MS s a
+ RSolve.MultiState: putMS :: s -> MS s ()
+ RSolve.PropLogic: (:&&) :: NF a -> NF a -> NF a
+ RSolve.PropLogic: (:&&:) :: WFF a -> WFF a -> WFF a
+ RSolve.PropLogic: (:=>:) :: WFF a -> WFF a -> WFF a
+ RSolve.PropLogic: (:||) :: NF a -> NF a -> NF a
+ RSolve.PropLogic: (:||:) :: WFF a -> WFF a -> WFF a
+ RSolve.PropLogic: Atom :: a -> WFF a
+ RSolve.PropLogic: AtomN :: a -> NF a
+ RSolve.PropLogic: Not :: WFF a -> WFF a
+ RSolve.PropLogic: assert :: AtomF a => WFF a -> MS (Set a) ()
+ RSolve.PropLogic: assertNF :: AtomF a => NF a -> MS (Set a) ()
+ RSolve.PropLogic: class (Show a, Ord a) => AtomF a
+ RSolve.PropLogic: data NF a
+ RSolve.PropLogic: data WFF a
+ RSolve.PropLogic: infixl 3 :||
+ RSolve.PropLogic: infixl 5 :&&
+ RSolve.PropLogic: instance GHC.Base.Functor RSolve.PropLogic.NF
+ RSolve.PropLogic: instance GHC.Base.Functor RSolve.PropLogic.WFF
+ RSolve.PropLogic: instance GHC.Classes.Eq a => GHC.Classes.Eq (RSolve.PropLogic.NF a)
+ RSolve.PropLogic: instance GHC.Classes.Eq a => GHC.Classes.Eq (RSolve.PropLogic.WFF a)
+ RSolve.PropLogic: instance GHC.Classes.Ord a => GHC.Classes.Ord (RSolve.PropLogic.NF a)
+ RSolve.PropLogic: instance GHC.Classes.Ord a => GHC.Classes.Ord (RSolve.PropLogic.WFF a)
+ RSolve.PropLogic: normal :: AtomF a => WFF a -> NF a
+ RSolve.PropLogic: notA :: AtomF a => a -> [a]
+ RSolve.PropLogic: unionEquations :: AtomF a => MS (Set a) () -> [[a]]
+ RSolve.Solver: class AtomF a => CtxSolver s a
+ RSolve.Solver: solve :: CtxSolver s a => a -> MS s ()
Files
- ChangeLog.md +6/−0
- README.md +123/−63
- RSolve.cabal +71/−35
- app/Main.hs +2/−0
- src/RSolve/BrMonad.hs +0/−30
- src/RSolve/HM.hs +208/−0
- src/RSolve/HM/Core.hs +0/−115
- src/RSolve/Infr.hs +0/−99
- src/RSolve/Logic.hs +6/−87
- src/RSolve/MapLike.hs +51/−0
- src/RSolve/MultiState.hs +43/−0
- src/RSolve/Options/Core.hs +0/−102
- src/RSolve/PropLogic.hs +72/−0
- src/RSolve/Solver.hs +8/−0
- test/Spec.hs +92/−0
+ ChangeLog.md view
@@ -0,0 +1,6 @@+## 1.0.0.0+- 2019-08-04+ - Removed the general solver tentatively(for maintainability and good design).+ - Separated the logic formulas from the problem domains.+ - Removed the solver for `Options`.+ - Re-implemented the solver for `HM`.
README.md view
@@ -1,93 +1,153 @@ # RSolve -[](hackage.haskell.org/package/RSolve)+[](https://hackage.haskell.org/package/RSolve) -A general solver for type checkers of programming languages and real world puzzles with complex constraints.+NOTE: NO LONGER for general logic programming, this package is now dedicated for the simple propositional logic. -## Preview+The README is going to get updated. -Here are 2 special cases presented in the following sections to show how powerful `RSolve` is.+## Propositional Logic -### The Most Graceful Hindley-Milner Unification+RSolve uses [disjunctive normal form](https://en.wikipedia.org/wiki/Disjunctive_normal_form) to solve logic problems. -Check `RSolve.HM.Core` and `RSolve.HM.Example`.+This disjunctive normal form works naturally with the logic problems where the atom formulas can be generalized to an arbitrary equation in the problem domain by introducing a problem domain specific solver. A vivid+example can be found at `RSolve.HM`, where+I implemented an extended algo-W for [HM unification](https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system). -Uncomment the code in `Main.hs` could reproduce following program: +To take advantage of RSolve, we should implement 2 classes:++- `AtomF`, which stands for the atom formula.++- `CtxSolver`, which stands for the way to solve a bunch of atom formulas.++However we might not need to a solver sometimes:+ ```haskell-check = do- let i = Prim Int- let f = Prim Float- let arrow = Op Arrow i f- -- u means undecided- u1 <- new- u2 <- new- u3 <- new- u4 <- new- -- u1 -> u2 where u1, u2 is not generic- let arrow_var = Op Arrow (Var u1) (Var u2)- -- int -> int- let arrow_inst1 = Op Arrow i i- -- float -> float- let arrow_inst2 = Op Arrow f f- -- a generic function- let arrow_generic = Forall [u3] $ Op Arrow (Var u3) (Var u3)+data Value = A | B | C | D+ deriving (Show, Eq, Ord, Enum) - let arrow_match = Op Arrow (Var u4) (Var u4)+data At = At {at_l :: String, at_r :: Value}+ deriving (Show, Eq, Ord) - _ <- solve $ Unify arrow arrow_var- _ <- solve $ Unify arrow_inst1 arrow_match- _ <- solve $ Unify arrow_generic arrow_inst1- _ <- solve $ Unify arrow_generic arrow_inst2- _ <- solveNeg+instance AtomF At where+ notA At {at_l = lhs, at_r = rhs} =+ let wholeSet = enumFrom (toEnum 0) :: [Value]+ contrasts = delete rhs wholeSet+ in [At {at_l = lhs, at_r = rhs'} | rhs' <- contrasts] - mapM require [Var u1, Var u2, arrow_inst1, arrow_inst2, arrow_generic, arrow_match]-```+infix 6 <==>+s <==> v = Atom $ At s v -output:+equations = do+ assert $ "a" <==> A :||: "a" <==> B+ assert $ Not ("a" <==> A) +main =+ let equationGroups = unionEquations equations+ in forM equationGroups print ```-u1 : Int-u2 : Float-arrow_inst1 : (Int -> Int)-arrow_inst2 : (Float -> Float)-arrow_generic : forall a2.(a2 -> a2)-arrow_match : (Int -> Int)+produces+```haskell+[At {at_l = "a", at_r = A},At {at_l = "a", at_r = B}]+[At {at_l = "a", at_r = A},At {at_l = "a", at_r = C}]+[At {at_l = "a", at_r = A},At {at_l = "a", at_r = D}]+[At {at_l = "a", at_r = B}]+[At {at_l = "a", at_r = B},At {at_l = "a", at_r = C}]+[At {at_l = "a", at_r = B},At {at_l = "a", at_r = C},At {at_l = "a", at_r = D}]+[At {at_l = "a", at_r = B},At {at_l = "a", at_r = D}] ``` -### N-Option Puzzles+According to the property of the problem domain, we can figure out that+only the 4-th(1-based indexing) equation group+`[At {at_l = "a", at_r = B}]`+will produce a feasible solution because symbol `a` can+only hold one value. -This implementation is presented at `RSolve.Options`, which provides the abstractions to solve all kinds of puzzles described with options.+When do we need a solver? For instance, type checking&inference. -A Hello World program could be found at `src/Main.hs` which solves a complex problem described with following link:+In this case, we need type checking environments to represent the checking states: -https://www.zhihu.com/question/68411978/answer/558913247.+```haskell+data TCEnv = TCEnv {+ _noms :: M.Map Int T -- nominal type ids+ , _tvars :: M.Map Int T -- type variables+ , _neqs :: S.Set (T, T) -- negation constraints+ }+ deriving (Show) +emptyTCEnv = TCEnv M.empty M.empty S.empty+``` -However, the much easier cases taking the same background as above problem (logic constraints described with four options `A, B, C, D`) could be enjoyale:+For sure we also need to represent the type: ```haskell-test2 = do- a <- store $ sol [A, B, C]- b <- store $ sol [B, C, D]- c <- store $ sol [C]- _ <- solve $ a `eq` b- _ <- solve $ b `neq` c- _ <- solveNeg -- `Not` condition requires this- _ <- solvePred -- unnecessary- mapM require [a, b, c]--main = do- format ["a", "b", "c"] . nub . L.map fst- $ runBr test2 emptyLState+data T+ = TVar Int+ | TFresh String+ | T :-> T+ | T :* T -- tuple+ | TForall (S.Set String) T+ | TApp T T -- type application+ | TNom Int -- nominal type index+ deriving (Eq, Ord) ``` -output:+Then the atom formula of HM unification is: +```haskell+data Unif+ = Unif {+ lhs :: T+ , rhs :: T+ , neq :: Bool -- lhs /= rhs or lhs == rhs?+ }+ deriving (Eq, Ord) ```-λ stack exec RSolve-====-"a" : Sol (fromList [B])-"b" : Sol (fromList [B])-"c" : Sol (fromList [C])++We then need to implement this:++```haskell+-- class AtomF a => CtxSolver s a where+-- solve :: a -> MS s ()+prune :: T -> MS TCEnv T -- MS: MultiState+instance CtxSolver TCEnv Unif where+ solver = ...+````++Finally we got this:++```haskell+infixl 6 <=>+a <=> b = Atom $ Unif {lhs=a, rhs=b, neq=False}+solu = do+ a <- newTVar+ b <- newTVar+ c <- newTVar+ d <- newTVar+ let [eqs] = unionEquations $+ do+ assert $ TVar a <=> TForall (S.fromList ["s"]) ((TFresh "s") :-> (TFresh "s" :* TFresh "s"))+ assert $ TVar a <=> (TVar b :-> (TVar c :* TVar d))+ assert $ TVar d <=> TNom 1+ -- return eqs+ forM_ eqs solve+ return eqs+ a <- prune $ TVar a+ b <- prune $ TVar b+ c <- prune $ TVar c+ return (a, b, c)++test :: Eq a => String -> a -> a -> IO ()+test msg a b+ | a == b = return ()+ | otherwise = print msg++main = do+ forM (unionEquations equations) print++ let (a, b, c):_ = map fst $ runMS solu emptyTCEnv+ test "1 failed" (show a) "@t1 -> @t1 * @t1"+ test "2 failed" (show b) "@t1"+ test "3 failed" (show c) "@t1" ```
RSolve.cabal view
@@ -1,41 +1,77 @@-name: RSolve-version: 0.1.0.1-synopsis: A general solver for equations-description: A general solver for type checkers of programming languages- and real world puzzles with complex constraints.-homepage: https://github.com/thautwarm/Rsolver#readme-license: MIT-license-file: LICENSE-author: thautwarm-maintainer: twshere@outlook.com-copyright: 2018 thautwarm-category: Language-build-type: Simple-cabal-version: >=1.10-extra-source-files: README.md+cabal-version: 1.12 +-- This file has been generated from package.yaml by hpack version 0.31.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: e5b30745fe99238706cc93bcd6a0c1fe3d35090d5dc5cabf244120d6d382d56c++name: RSolve+version: 2.0.0.0+description: A general solver for equations+category: Logic,Unification+homepage: https://github.com/thautwarm/RSolve#readme+bug-reports: https://github.com/thautwarm/RSolve/issues+author: thautwarm+maintainer: twshere@outlook.com+copyright: 2018, 2019 thautwarm+license: MIT+license-file: LICENSE+build-type: Simple+extra-source-files:+ README.md+ ChangeLog.md+ source-repository head- type: git- location: https://github.com/thautwarm/Rsolver.git+ type: git+ location: https://github.com/thautwarm/RSolve library- hs-source-dirs: src- default-language: Haskell2010- build-depends: base >= 4 && < 5- , containers- exposed-modules: RSolve.BrMonad- , RSolve.Infr- , RSolve.Logic- , RSolve.HM.Core- , RSolve.Options.Core+ exposed-modules:+ RSolve.HM+ RSolve.Logic+ RSolve.MapLike+ RSolve.MultiState+ RSolve.PropLogic+ RSolve.Solver+ other-modules:+ Paths_RSolve+ hs-source-dirs:+ src+ build-depends:+ base >=4.7 && <5+ , containers+ , lens+ , mtl+ default-language: Haskell2010 --- executable RSolveExample--- hs-source-dirs: src--- main-is: Main.hs--- build-depends: base >= 4 && < 5--- , RSolve--- , containers--- default-language: Haskell2010--- other-modules: RSolve.HM.Example--- , RSolve.Options.Example+executable RSolve-exe+ main-is: Main.hs+ other-modules:+ Paths_RSolve+ hs-source-dirs:+ app+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ RSolve+ , base >=4.7 && <5+ , containers+ , lens+ , mtl+ default-language: Haskell2010 +test-suite RSolve-test+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ other-modules:+ Paths_RSolve+ hs-source-dirs:+ test+ ghc-options: -threaded -rtsopts -with-rtsopts=-N+ build-depends:+ RSolve+ , base >=4.7 && <5+ , containers+ , lens+ , mtl+ default-language: Haskell2010
+ app/Main.hs view
@@ -0,0 +1,2 @@+module Main where+main = putStrLn "No CLI support yet"
− src/RSolve/BrMonad.hs
@@ -1,30 +0,0 @@-module RSolve.BrMonad where-import Control.Monad-import Control.Monad.Fail-import Control.Applicative--newtype Br s a = Br {runBr :: s -> [(a, s)]}--instance Functor (Br s) where- fmap = liftM--instance Applicative (Br s) where- pure = return- (<*>) = ap--instance MonadFail (Br s) where- fail _ = empty--instance Monad (Br s) where- m >>= k =- Br $ \s ->- let xs = runBr m s- in join [ runBr (k a) s | (a, s) <- xs]- return a = Br $ \s -> [(a, s)]--instance Alternative (Br s) where- empty = Br $ const []- ma <|> mb = Br $ \s -> runBr ma s ++ runBr mb s--getBy f = Br $ \s -> [(f s, s)]-putBy f = Br $ \s -> [((), f s)]
+ src/RSolve/HM.hs view
@@ -0,0 +1,208 @@+-- | HM unification implementations based on propositional logics,+-- based on nominal type system.+-- Author: Taine Zhao(thautwarm)+-- Date: 2019-08-04+-- License: MIT+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module RSolve.HM+where+import RSolve.Logic+import RSolve.Solver+import RSolve.MultiState+import Control.Lens (Lens', view, over, makeLenses)+import Control.Applicative+import Control.Monad+import Debug.Trace++import qualified Data.List as L+import qualified Data.Map as M+import qualified Data.Set as S++type Fix a = a -> a++infixl 6 :->, :*++data T+ = TVar Int+ | TFresh String+ | T :-> T+ | T :* T -- tuple+ | TForall (S.Set String) T+ | TApp T T -- type application+ | TNom Int -- nominal type index+ deriving (Eq, Ord)++deConsTOp :: T -> Maybe (T -> T -> T, T, T)+deConsTOp = \case+ a :-> b -> Just ((:->), a, b)+ a :* b -> Just ((:*), a, b)+ TApp a b -> Just (TApp, a, b)+ _ -> Nothing++instance Show T where+ show = \case+ TVar idx -> "@" ++ show idx+ TFresh s -> s+ a :-> b -> showNest a ++ " -> " ++ show b+ a :* b -> showNest a ++ " * " ++ show b+ TForall l t -> "forall " ++ (unwords $ S.toList l) ++ ". " ++ show t+ TApp t1 t2 -> show t1 ++ " " ++ showNest t2+ TNom i -> "@t" ++ show i+ where+ showNest s+ | isNest s = "(" ++ show s ++ ")"+ | otherwise = show s+ isNest s = case s of+ TApp _ _ -> True+ TForall _ s -> isNest s+ _ :-> _ -> True+ _ :* _ -> True+ _ -> False++data Unif+ = Unif {+ lhs :: T+ , rhs :: T+ , neq :: Bool+ }+ deriving (Eq, Ord)++instance Show Unif where+ show Unif {lhs, rhs, neq} =+ let op = if neq then " /= " else " == "+ in show lhs ++ op ++ show rhs++instance AtomF Unif where+ notA a@Unif {neq} = [a {neq = not neq}]++data TCEnv = TCEnv {+ _noms :: M.Map Int T -- nominal type ids+ , _tvars :: M.Map Int T -- type variables+ , _neqs :: S.Set (T, T) -- negation constraints+ }+ deriving (Show)++emptyTCEnv = TCEnv M.empty M.empty S.empty++makeLenses ''TCEnv++newTVar :: MS TCEnv Int+newTVar = do+ i <- getsMS $ M.size . view tvars+ modifyMS $ over tvars $ M.insert i (TVar i)+ return i++newTNom :: MS TCEnv Int+newTNom = do+ i <- getsMS $ M.size . view noms+ modifyMS $ over noms $ M.insert i (TNom i)+ return i++loadTVar :: Int -> MS TCEnv T+loadTVar i = getsMS $ (M.! i) . view tvars++occurIn :: Int -> T -> MS TCEnv Bool+occurIn l = contains+ where+ contains (deConsTOp -> Just (_, a, b)) = (||) <$> contains a <*> contains b+ contains (TNom _) = return False+ contains (TForall _ a) = contains a+ contains (TFresh _) = return False+ contains (TVar a)+ | a == l = return True+ | otherwise = do+ tvar <- loadTVar a+ case tvar of+ TVar a' | a' == a -> return False+ _ -> contains tvar++free :: M.Map String T -> T -> T+free m = mkFree+ where+ mkFree (deConsTOp -> Just (op, a, b)) = op (mkFree a) (mkFree b)+ mkFree a@(TNom i) = a+ mkFree (TForall n t) = TForall n $ flip free t $ M.withoutKeys m n+ mkFree a@(TVar _) = a+ mkFree a@(TFresh id) = M.findWithDefault a id m++prune :: T -> MS TCEnv T+prune = \case+ (deConsTOp -> Just (op, a, b)) -> op <$> prune a <*> prune b+ a@(TNom i) -> return a+ TVar i ->+ loadTVar i >>= \case+ a@(TVar i') | i' == i -> return a+ a -> do+ t <- prune a+ update i t+ return t++ a@(TFresh _) -> return a+ TForall a b -> TForall a <$> prune b++update :: Int -> T -> MS TCEnv ()+update i t = modifyMS $ over tvars $ M.insert i t++addNEq :: (T, T) -> MS TCEnv ()+addNEq t = modifyMS $ over neqs (S.insert t)++unify :: Fix (Unif -> MS TCEnv ())+unify self Unif {lhs, rhs, neq=True} = addNEq (lhs, rhs)++unify self Unif {lhs=TNom a, rhs=TNom b}+ | a == b = return ()+ | otherwise = empty++unify self Unif {lhs=TVar a, rhs = TVar b} = do+ recursive <- occurIn a (TVar b)+ if recursive+ then error "ill formed definition like a = a -> b"+ else update a (TVar b)++unify self Unif {lhs=TVar id, rhs, neq} = update id rhs++unify self a@Unif {lhs, rhs=rhs@(TVar _)} = self a {lhs=rhs, rhs=lhs}++-- type operators are not frist class+unify self Unif {lhs=l1 :-> l2, rhs= r1 :-> r2} =+ self Unif {lhs=l1, rhs=r1, neq=False} >>+ self Unif {lhs=l2, rhs=r2, neq=False}++unify self Unif {lhs=l1 :* l2, rhs= r1 :* r2} =+ self Unif {lhs=l1, rhs=r1, neq=False} >>+ self Unif {lhs=l2, rhs=r2, neq=False}++-- TODO: type aliases?+unify self Unif {lhs=TApp l1 l2, rhs= TApp r1 r2} =+ self Unif {lhs=l1, rhs=r1, neq=False} >>+ self Unif {lhs=l2, rhs=r2, neq=False}++unify self Unif {lhs=TForall freevars poly, rhs} = do+ pairs <- mapM freepair $ S.toList freevars+ let freemap = M.fromList pairs+ let l = free freemap poly+ self Unif {lhs=l, rhs=rhs, neq=False}+ where freepair freevar = (freevar,) . TVar <$> newTVar++unify self a@Unif {lhs, rhs=rhs@(TForall _ _)} =+ self a {lhs=rhs, rhs=lhs}++instance CtxSolver TCEnv Unif where+ solve =+ let frec = unify (pruneUnif >=> frec)+ in pruneUnif >=> frec+ where+ pruneUnif a@Unif {neq=True} = return a+ pruneUnif a@Unif {lhs, rhs} = do+ lhs <- prune lhs+ rhs <- prune rhs+ return $ a {lhs=lhs , rhs=rhs}+++
− src/RSolve/HM/Core.hs
@@ -1,115 +0,0 @@-{-# LANGUAGE GADTs #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE TupleSections #-}--- https://github.com/thautwarm/reFining/blob/master/DotNet/reFining/reFining--module RSolve.HM.Core where-import RSolve.BrMonad-import RSolve.Infr-import RSolve.Logic-import Control.Applicative-import qualified Data.Map as M--type Id = Int--data TypeOp = Arrow | Join | Stmt- deriving (Show, Eq, Ord)--data Prim = Int | Float | Char- deriving (Show, Eq, Ord)---data Core where- Prim :: Prim -> Core-- Op :: TypeOp -> Core -> Core -> Core-- Forall :: [Id] -> Core -> Core-- Var :: Id -> Core- deriving (Eq)--instance Show Core where- show (Prim a) = show a- show (Op Arrow a b) =- "(" ++ show a ++ " -> " ++ show b ++ ")"- show (Op Join a b) = show a ++ ", " ++ show b- show (Op Stmt a b) = show a ++ ";\n" ++ show b- show (Forall xs b) =- let f a b = a ++ " a" ++ show b- in foldl f "forall " xs ++ "." ++ show b- show (Var a) = "a" ++ show a--free :: M.Map Id Core -> Core -> Core-free m = mkFree- where- mkFree a@(Prim _) = a- mkFree (Op op a b) = Op op (mkFree a) (mkFree b)- mkFree (Forall a b) = Forall a (mkFree b)- mkFree a@(Var id) =- M.findWithDefault a id m--occurIn :: Addr -> Addr -> Br (LState Core) Bool-occurIn l = contains . Var- where- contains (Prim _) = return False-- contains (Var a) =- if a == l then return True- else tryLoad a >>= \case- Just a -> contains a- _ -> return False-- contains (Op _ a b) = (||) <$> contains a <*> contains b- contains (Forall _ a) = contains a--instance Reference Core where- mkRef = Var- isRef (Var a) = Just a- isRef _ = Nothing---instance Unify Core where- prune v@(Var a) = tryLoad a >>= \case- Just var -> prune var- _ -> return v-- prune a@(Prim _) = return a-- prune (Forall a b) = Forall a <$> prune b- prune (Op op a b) = Op op <$> prune a <*> prune b-- unify (Prim a) (Prim b) =- if a == b then return ()- else empty-- unify l@(Var a) r@(Var b)- | a == b = return ()- | otherwise = do- recursive <- occurIn a b- if recursive- then error "ill formed definition like a = a -> b"- else update a r-- unify l r@(Var _) = unify r l-- unify (Var id) r = update id r-- -- type operators are not frist class- unify (Op opl l1 l2) (Op opr r1 r2) =- if opl /= opr then empty- else- unify l1 r1 >> unify l2 r2-- unify (Forall freevars poly) r = do- pairs <- mapM freepair freevars- let freemap = M.fromList pairs- let l = free freemap poly- unify l r- where- freepair freevar = (freevar,) <$> mkRef <$> new-- unify l r@(Forall _ _) = unify r l--
− src/RSolve/Infr.hs
@@ -1,99 +0,0 @@-module RSolve.Infr where-import RSolve.BrMonad-import Control.Applicative-import qualified Data.Set as S-import qualified Data.Map as M-import qualified Data.List as L--type Addr = Int-class Eq a => Reference a where- -- reference can be stored in Map- isRef :: a -> Maybe Addr- mkRef :: Addr -> a--class Reference a => Unify a where- prune :: a -> Br (LState a) a- unify :: a -> a -> Br (LState a) ()- complement :: a -> a -> Br (LState a) ()- complement a b =- if a == b then return ()- else empty--class EnumSet a where- toEnumerable :: Br (LState a) ()---data Allocator a =- Allocator { storage :: M.Map Addr a- , addr :: Addr }- deriving (Show)---data LState a =- LState { allocator :: Allocator a- , negPairs :: [(a, a)]- , constrains :: [Br (LState a) Bool] }--allocator' st (LState _ negs cs) = LState st negs cs-negPairs' negs (LState st _ cs) = LState st negs cs-constrains' cs (LState st negs _) = LState st negs cs---inc :: Reference a => Allocator a -> (Addr, Allocator a)-inc (Allocator s c) = (c, Allocator s $ c + 1)--alloc :: Reference a => a -> Allocator a -> (Addr, Allocator a)-alloc a (Allocator s c) = (c, Allocator (M.insert c a s) (c + 1))--renew :: Reference a => Addr -> a -> Allocator a -> Allocator a-renew addr obj r@(Allocator s c) =- case isRef obj of- Just addr' | addr' == addr -> r -- avoid recursive definition- _ -> Allocator (M.insert addr obj s) c--store :: (Reference a, Eq a) => a -> Br (LState a) a-store a = do- st <- getBy allocator- let (n, st') = alloc a st- _ <- putBy $ allocator' st'- return $ mkRef n----- update state-update :: Reference a => Addr -> a -> Br (LState a) ()-update addr obj = getBy allocator >>= putBy . allocator' . renew addr obj---load :: Addr -> Br (LState a) a-load addr =- ((M.! addr) . storage) <$> getBy allocator---tryLoad :: Addr -> Br (LState a) (Maybe a)-tryLoad addr =- (M.lookup addr . storage) <$> getBy allocator----- for the system which take leverage of generics-new :: Reference a => Br (LState a) Addr-new = do- st <- getBy allocator- let (addr', st') = inc st- _ <- putBy $ allocator' st'- return addr'--negUnify :: Reference a => a -> a -> Br (LState a) ()-negUnify a b = do- negs <- getBy negPairs- if check negs then- putBy $ negPairs' ((a, b) : negs)- else return ()- where- check [] = True- check ((a', b'):xs)- | (a', b') == (a, b) || (a', b') == (b, a) = False- | otherwise = check xs---emptyAllocator = Allocator M.empty 0-emptyLState = LState emptyAllocator [] []
src/RSolve/Logic.hs view
@@ -1,89 +1,8 @@-{-# LANGUAGE GADTs #-} module RSolve.Logic where-import RSolve.BrMonad-import RSolve.Infr-import Data.List (nub)-import Control.Applicative -data Cond a where- Unify :: Unify a => a -> a -> Cond a- Not :: Cond a -> Cond a- Pred :: Br (LState a) Bool -> Cond a-- Or :: Cond a -> Cond a -> Cond a- And :: Cond a -> Cond a -> Cond a- Imply :: Cond a -> Cond a -> Cond a--solve :: Cond a -> Br (LState a) ()-solve (Unify l r) = do- l <- prune l- r <- prune r- unify l r--solve (Or l r) =- solve l <|> solve (And (Not l) r)--solve (And l r) =- solve l >> solve r--solve (Imply l r) =- solve (Not l) <|> solve r--solve (Pred c) = do- cs <- getBy constrains- putBy $ constrains' (c:cs)--solve (Not emmm) =- case emmm of- Pred c -> solve $ Pred (not <$> c)- Not emmm -> solve emmm- Or l r -> solve $ And (Not l)(Not r)- And l r -> solve $ Or (Not l)(Not r)- Imply l r -> solve $ And l (Not r)- Unify l r -> do- l <- prune l- r <- prune r- negUnify l r--solveNeg :: Unify a => Br (LState a) ()-solveNeg = do- negs <- getBy negPairs- negs <- pruneTuples negs- solveNeg' $ nub (negs)- where- pruneTuples [] = return []- pruneTuples ((a, b):xs) = do- a <- prune a- b <- prune b- xs' <- pruneTuples xs- let- process (Just a) (Just b) = x:xs- where- mkRef2 a b = (mkRef a, mkRef b)- x = if a > b then mkRef2 a b else mkRef2 b a- process _ _ = (a, b):xs'- return $ process (isRef a) (isRef b)- solveNeg' [] = return ()- solveNeg' ((a,b):xs) =- (a `complement` b) >> solveNeg' xs--solvePred :: EnumSet a => Br (LState a) ()-solvePred = do- _ <- toEnumerable- cs <- getBy constrains- checkPredicate cs- where- checkPredicate [] = return ()- checkPredicate (x:xs) = do- x <- x- if x then checkPredicate xs- else empty--require :: Unify a => a -> Br (LState a) a-require a = do- a <- prune a- case isRef a of- Just a -> load a- _ -> return a--+-- atom formula+class (Show a, Ord a) => AtomF a where+ -- | Specifies how to handle the negations.+ -- For the finite and enumerable solutions,+ -- we can return its supplmentary set.+ notA :: a -> [a]
+ src/RSolve/MapLike.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}++module RSolve.MapLike where+import Data.Maybe+import Data.Kind+import Prelude hiding (lookup, insert)+import qualified Data.Map as M+import qualified Data.List as L+import qualified Data.Set as S++class MapLike m k v | m -> k, m -> v where+ lookup :: k -> m -> Maybe v+ (!) :: m -> k -> v+ m ! k = fromJust (lookup k m)+ insert :: k -> v -> m -> m+ adjust :: (v -> v) -> k -> m -> m+ member :: k -> m -> Bool+ update :: (v -> Maybe v) -> k -> m -> m+++instance Ord k => MapLike (M.Map k v) k v where+ lookup = M.lookup+ (!) = (M.!)+ insert = M.insert+ adjust = M.adjust+ member = M.member+ update = M.update++instance Eq k => MapLike [(k, v)] k v where+ lookup = L.lookup+ insert k v = \case+ [] -> [(k, v)]+ (k', v'):xs | k' == k -> (k, v):xs+ x:xs -> x:insert k v xs+ adjust f k = \case+ [] -> []+ (k', v):xs | k' == k -> (k', f v):xs+ x:xs -> x:adjust f k xs+ k `member` m = case lookup k m of+ Just _ -> True+ Nothing -> False+ update f k = \case+ [] -> []+ hd@(k', v):xs | k == k' ->+ case f v of+ Just v' -> (k, v'):tl+ Nothing -> hd:tl+ where tl = update f k xs
+ src/RSolve/MultiState.hs view
@@ -0,0 +1,43 @@+-- | state monads extended to have branches+-- Author: Taine Zhao(thautwarm)+-- Date: 2018-12+-- License: MIT+module RSolve.MultiState where+import Control.Monad+import Control.Monad.Fail+import Control.Applicative++newtype MS s a = MS {runMS :: s -> [(a, s)]}++instance Functor (MS s) where+ fmap = liftM++instance Applicative (MS s) where+ pure = return+ (<*>) = ap++instance MonadFail (MS s) where+ fail _ = empty++instance Monad (MS s) where+ m >>= k =+ MS $ \s ->+ let xs = runMS m s+ in join [runMS (k a) s' | (a, s') <- xs]+ return a = MS $ \s -> [(a, s)]++instance Alternative (MS s) where+ empty = MS $ const []+ ma <|> mb = MS $ \s -> runMS ma s ++ runMS mb s++getMS :: MS s s+getMS = MS $ \s -> [(s, s)]++putMS :: s -> MS s ()+putMS s = MS $ const [((), s)]++getsMS :: (s -> a) -> MS s a+getsMS f = MS $ \s -> [(f s, s)]++modifyMS :: (s -> s) -> MS s ()+modifyMS f = MS $ \s -> [((), f s)]
− src/RSolve/Options/Core.hs
@@ -1,102 +0,0 @@-module RSolve.Options.Core where-import RSolve.BrMonad-import RSolve.Infr-import RSolve.Logic-import Control.Monad-import Control.Applicative-import Prelude hiding (not, or, and)-import qualified Data.Set as S-import qualified Data.Map as M-import qualified Data.List as L--data Option = A | B | C | D- deriving (Eq, Show, Ord, Enum)--data Term = Var Int | Sol (S.Set Option)- deriving (Eq, Show)--pruneSol :: Term -> Br (LState Term) (Int, Maybe (S.Set Option))-pruneSol (Var addr) = do- t <- load addr- case t of- Var addr' -> do- r @ (addrLast, _) <- pruneSol t- update addr (Var addrLast) >> return r- Sol lxs ->- return (addr, Just lxs)- -- if S.null lxs then error "emmm"- -- else return (addr, Just lxs)--pruneSol r @ (Sol xs) =- store r >>= \(Var addr) ->- return (addr, Just xs)--instance Reference Term where- isRef (Var addr) = Just addr- isRef _ = Nothing- mkRef a = Var a----instance Unify Term where- prune a = pruneSol a >>= return . Var . fst- unify l r =- pruneSol l >>= \(lFrom, lxsm) ->- pruneSol r >>= \(rFrom, rxsm) ->- case (lxsm, rxsm) of- (Nothing, _) -> update lFrom (Var rFrom)- (Just lxs, _) | S.null lxs -> empty- (_, Just rxs) | S.null rxs -> empty- (Just _, Nothing ) -> unify r l- (Just lxs, Just rxs) ->- let xs = S.intersection lxs rxs in- if S.null xs- then empty- else do- new <- store $ Sol xs- update lFrom new >> update rFrom new-- complement l r = do- (l, Just lxs) <- pruneSol l- (r, Just rxs) <- pruneSol r- case (S.size lxs, S.size rxs) of- (1, 1) | lxs == rxs -> empty- (1, 1) | lxs /= rxs -> return ()- (nl, nr) | nl < nr -> complement (Var r) (Var l)- (nl, nr) | nl >= nr -> do- let- x:xs = L.map f . S.toList $ rxs- f :: Option -> Br (LState Term) ()- f re =- let lnew_set = S.delete re lxs- in- if S.null lnew_set- then empty- else do- lnew <- store . Sol $ lnew_set- rnew <- store . Sol . S.singleton $ re- update l lnew >> update r rnew- L.foldl (<|>) x xs--instance EnumSet Term where- toEnumerable = do- st <- getBy $ storage . allocator- M.foldlWithKey f (return ()) st- where- f :: Br (LState Term) () -> Addr -> Term -> Br (LState Term) ()- f a k b =- case b of- Var _ -> a- Sol set ->- let- lst = S.toList set- g :: [Option] -> Br (LState Term) ()- g [] = error "unexpected"- g (x:xs) = do- x <- store . Sol . S.singleton $ x- let s = update k x- case xs of- [] -> s- _ -> s <|> g xs- in a >> g lst-
+ src/RSolve/PropLogic.hs view
@@ -0,0 +1,72 @@+-- | Propositional logic infrastructures+-- Author: Taine Zhao(thautwarm)+-- Date: 2019-08-03+-- License: MIT+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE DeriveFunctor #-}++module RSolve.PropLogic+ (AtomF(..), WFF(..), NF(..), assertNF, normal, assert, unionEquations)+where++import RSolve.Logic+import RSolve.MultiState+import Control.Applicative ((<|>))+import qualified Data.Set as S++infixl 5 :&&, :&&:+infixl 3 :||, :||:, :=>:++data WFF a+ -- | Atom formula, should be specified by the problem+ = Atom a+ | Not (WFF a)+ -- | And+ | WFF a :&&: WFF a+ -- | Or+ | WFF a :||: WFF a+ -- | Implication+ | WFF a :=>: WFF a+ deriving (Functor, Eq, Ord)++-- | normalized WWF, where '[NF a]' the disjunctive normal form.+data NF a+ = AtomN a+ | NF a :&& NF a+ | NF a :|| NF a+ deriving (Functor, Eq, Ord)++normal :: AtomF a => WFF a -> NF a+normal = \case+ Atom a -> AtomN a+ p1 :&&: p2 -> normal p1 :&& normal p2+ p1 :||: p2 -> normal p1 :|| normal (Not p1 :&&: p2)+ Not (Atom a) ->+ case map AtomN $ notA a of+ hd:tl -> foldl (:||) hd tl+ [] -> error $ "Supplementary set of " ++ show a ++ " is empty!"+ Not (Not p) -> normal p+ Not (p1 :&&: p2) -> normal (Not p1) :|| normal (Not p2)+ Not (p1 :||: p2) -> normal (Not p1) :&& normal (Not p2)+ Not (p1 :=>: p2) -> normal (Not p1 :||: p2)++assertNF :: AtomF a => NF a -> MS (S.Set a) ()+assertNF = \case+ AtomN a -> modifyMS (S.insert a)+ p1 :&& p2 -> assertNF p1 >> assertNF p2+ p1 :|| p2 -> assertNF p1 <|> assertNF p2+++-- | Use a propositinal logic formula to build logic equations+-- incrementally.+assert :: AtomF a => WFF a -> MS (S.Set a) ()+assert = assertNF . normal++-- | Produced a list of disjunctions of conjunctive clauses.+unionEquations :: AtomF a => MS (S.Set a) () -> [[a]]+unionEquations m =+ -- get states+ let sts = map snd $ runMS m S.empty+ -- unique states+ in map S.toList . S.toList . S.fromList $ sts+
+ src/RSolve/Solver.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE MultiParamTypeClasses #-}+module RSolve.Solver where+import RSolve.Logic+import RSolve.MultiState++class AtomF a => CtxSolver s a where+ -- | Give a atom formula and solve it+ solve :: a -> MS s ()
+ test/Spec.hs view
@@ -0,0 +1,92 @@+-- import RSolve.Options.Example+-- import RSolve.HM.Example+++-- test1 =+-- putStrLn "HM unification" >>+-- hmUnificationExample >>+-- putStrLn "4-option puzzles" >>+-- optionExample++-- main = print 233+++-- test2 = do+-- a <- store $ sol [A, B, C]+-- b <- store $ sol [B, C, D]+-- c <- store $ sol [C]+-- _ <- solve $ a `eq` b+-- _ <- solve $ b `neq` c+-- _ <- solveNeg -- `Not` condition requires this+-- _ <- solvePred -- unnecessary+-- mapM require [a, b, c]++-- main = do+-- format ["a", "b", "c"] . nub . L.map fst+-- $ runBr test2 emptyLState++import RSolve.HM+import RSolve.PropLogic+import RSolve.MultiState+import RSolve.Solver+import Control.Monad++import qualified Data.Set as S++import Data.List (delete)+import Control.Monad++data Value = A | B | C | D+ deriving (Show, Eq, Ord, Enum)++data At = At {at_l :: String, at_r :: Value}+ deriving (Show, Eq, Ord)++instance AtomF At where+ notA At {at_l = lhs, at_r = rhs} =+ let wholeSet = enumFrom (toEnum 0) :: [Value]+ contrasts = delete rhs wholeSet+ in [At {at_l = lhs, at_r = rhs'} | rhs' <- contrasts]++infix 6 <==>+s <==> v = Atom $ At s v+equations = do+ assert $ "a" <==> A :||: "a" <==> B+ assert $ "b" <==> C :||: "b" <==> D+ assert $ Not ("a" <==> A)+ assert $ Not ("a" <==> B :=>: "b" <==> C)+++infixl 6 <=>+a <=> b = Atom $ Unif {lhs=a, rhs=b, neq=False}+solu = do+ a <- newTVar+ b <- newTVar+ c <- newTVar+ d <- newTVar+ let [eqs] = unionEquations $+ do+ assert $ TVar a <=> TForall (S.fromList ["s"]) ((TFresh "s") :-> (TFresh "s" :* TFresh "s"))+ assert $ TVar a <=> (TVar b :-> (TVar c :* TVar d))+ assert $ TVar d <=> TNom 1+ forM_ eqs solve+ a <- prune $ TVar a+ b <- prune $ TVar b+ c <- prune $ TVar c+ return (a, b, c)++test :: Eq a => String -> a -> a -> IO ()+test msg a b+ | a == b = return ()+ | otherwise = print msg++main = do+ forM (unionEquations equations) $ \xs ->+ case xs of+ [a, b] -> print xs+ _ -> return ()++ let (a, b, c):_ = map fst $ runMS solu emptyTCEnv+ test "1 failed" (show a) "@t1 -> @t1 * @t1"+ test "2 failed" (show b) "@t1"+ test "3 failed" (show c) "@t1"