{"id":22018831,"url":"https://github.com/thautwarm/rsolve","last_synced_at":"2025-05-07T03:28:08.204Z","repository":{"id":62435497,"uuid":"162912091","full_name":"thautwarm/RSolve","owner":"thautwarm","description":"Ask for solutions.","archived":false,"fork":false,"pushed_at":"2019-08-05T03:12:16.000Z","size":2940,"stargazers_count":19,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-05-01T14:49:23.044Z","etag":null,"topics":["logic-programming","solvers"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thautwarm.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-23T17:46:36.000Z","updated_at":"2020-02-17T01:24:05.000Z","dependencies_parsed_at":"2022-11-01T21:15:53.482Z","dependency_job_id":null,"html_url":"https://github.com/thautwarm/RSolve","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thautwarm%2FRSolve","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thautwarm%2FRSolve/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thautwarm%2FRSolve/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thautwarm%2FRSolve/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thautwarm","download_url":"https://codeload.github.com/thautwarm/RSolve/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252806073,"owners_count":21807150,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["logic-programming","solvers"],"created_at":"2024-11-30T05:14:17.664Z","updated_at":"2025-05-07T03:28:08.186Z","avatar_url":"https://github.com/thautwarm.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RSolve\n\n[![](https://img.shields.io/hackage/v/RSolve.svg)](https://hackage.haskell.org/package/RSolve)\n\nNOTE: NO LONGER for general logic programming, this package is now dedicated for the simple propositional logic.\n\nThe README is going to get updated.\n\n## Propositional Logic\n\nRSolve uses [disjunctive normal form](https://en.wikipedia.org/wiki/Disjunctive_normal_form) to solve logic problems.\n\nThis 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\nexample can be found at `RSolve.HM`, where\nI implemented an extended algo-W for [HM unification](https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system).\n\n\nTo take advantage of RSolve, we should implement 2 classes:\n\n- `AtomF`, which stands for the atom formula.\n\n- `CtxSolver`, which stands for the way to solve a bunch of atom formulas.\n\nHowever we might not need to a solver sometimes:\n\n```haskell\ndata Value = A | B | C | D\n    deriving (Show, Eq, Ord, Enum)\n\ndata At = At {at_l :: String, at_r :: Value}\n    deriving (Show, Eq, Ord)\n\ninstance AtomF At where\n    notA At {at_l = lhs, at_r = rhs} =\n        let wholeSet  = enumFrom (toEnum 0) :: [Value]\n            contrasts = delete rhs wholeSet\n        in [At {at_l = lhs, at_r = rhs'} | rhs' \u003c- contrasts]\n\ninfix 6 \u003c==\u003e\ns \u003c==\u003e v = Atom $ At s v\n\nequations = do\n    assert $ \"a\" \u003c==\u003e A :||: \"a\" \u003c==\u003e B\n    assert $ Not (\"a\" \u003c==\u003e A)\n\nmain =\n  let equationGroups = unionEquations equations\n  in forM equationGroups print\n```\nproduces\n```haskell\n[At {at_l = \"a\", at_r = A},At {at_l = \"a\", at_r = B}]\n[At {at_l = \"a\", at_r = A},At {at_l = \"a\", at_r = C}]\n[At {at_l = \"a\", at_r = A},At {at_l = \"a\", at_r = D}]\n[At {at_l = \"a\", at_r = B}]\n[At {at_l = \"a\", at_r = B},At {at_l = \"a\", at_r = C}]\n[At {at_l = \"a\", at_r = B},At {at_l = \"a\", at_r = C},At {at_l = \"a\", at_r = D}]\n[At {at_l = \"a\", at_r = B},At {at_l = \"a\", at_r = D}]\n```\n\nAccording to the property of the problem domain, we can figure out that\nonly the 4-th(1-based indexing) equation group\n`[At {at_l = \"a\", at_r = B}]`\nwill produce a feasible solution because symbol `a` can\nonly hold one value.\n\nWhen do we need a solver? For instance, type checking\u0026inference.\n\nIn this case, we need type checking environments to represent the checking states:\n\n```haskell\ndata TCEnv = TCEnv {\n          _noms  :: M.Map Int T  -- nominal type ids\n        , _tvars :: M.Map Int T  -- type variables\n        , _neqs  :: S.Set (T, T) -- negation constraints\n    }\n    deriving (Show)\n\nemptyTCEnv = TCEnv M.empty M.empty S.empty\n```\n\nFor sure we also need to represent the type:\n\n```haskell\ndata T\n    = TVar Int\n    | TFresh String\n    | T :-\u003e T\n    | T :*  T -- tuple\n    | TForall (S.Set String) T\n    | TApp T T -- type application\n    | TNom Int -- nominal type index\n    deriving (Eq, Ord)\n```\n\nThen the atom formula of HM unification is:\n\n```haskell\ndata Unif\n    = Unif {\n          lhs :: T\n        , rhs :: T\n        , neq :: Bool -- lhs /= rhs or  lhs == rhs?\n      }\n  deriving (Eq, Ord)\n```\n\nWe then need to implement this:\n\n```haskell\n-- class AtomF a =\u003e CtxSolver s a where\n--     solve :: a -\u003e MS s ()\nprune :: T -\u003e MS TCEnv T -- MS: MultiState\ninstance CtxSolver TCEnv Unif where\n  solver = ...\n````\n\nFinally we got this:\n\n```haskell\ninfixl 6 \u003c=\u003e\na \u003c=\u003e b = Atom $ Unif {lhs=a, rhs=b, neq=False}\nsolu = do\n    a \u003c- newTVar\n    b \u003c- newTVar\n    c \u003c- newTVar\n    d \u003c- newTVar\n    let [eqs] = unionEquations $\n                do\n                assert $ TVar a \u003c=\u003e TForall (S.fromList [\"s\"]) ((TFresh \"s\") :-\u003e (TFresh \"s\" :* TFresh \"s\"))\n                assert $ TVar a \u003c=\u003e (TVar b :-\u003e (TVar c :* TVar d))\n                assert $ TVar d \u003c=\u003e TNom 1\n    -- return eqs\n    forM_ eqs solve\n    return eqs\n    a \u003c- prune $ TVar a\n    b \u003c- prune $ TVar b\n    c \u003c- prune $ TVar c\n    return (a, b, c)\n\ntest :: Eq a =\u003e String -\u003e a -\u003e a -\u003e IO ()\ntest msg a b\n    | a == b = return ()\n    | otherwise = print msg\n\nmain = do\n    forM (unionEquations equations) print\n\n    let (a, b, c):_ = map fst $ runMS solu emptyTCEnv\n    test \"1 failed\" (show a) \"@t1 -\u003e @t1 * @t1\"\n    test \"2 failed\" (show b) \"@t1\"\n    test \"3 failed\" (show c) \"@t1\"\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthautwarm%2Frsolve","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthautwarm%2Frsolve","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthautwarm%2Frsolve/lists"}