{"id":18774497,"url":"https://github.com/mmzk1526/hrolog","last_synced_at":"2025-12-14T10:30:17.554Z","repository":{"id":65593480,"uuid":"591755638","full_name":"MMZK1526/Hrolog","owner":"MMZK1526","description":"A Prolog-like language","archived":false,"fork":false,"pushed_at":"2023-06-10T15:52:44.000Z","size":258,"stargazers_count":2,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-12-29T08:43:21.946Z","etag":null,"topics":["functional-programming","haskell","interpreter","prolog"],"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/MMZK1526.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-21T19:05:30.000Z","updated_at":"2023-07-11T12:24:58.000Z","dependencies_parsed_at":"2024-11-07T19:41:17.296Z","dependency_job_id":"b8a55e14-a6d6-4382-9e38-aa8014f7ce1f","html_url":"https://github.com/MMZK1526/Hrolog","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MMZK1526%2FHrolog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MMZK1526%2FHrolog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MMZK1526%2FHrolog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MMZK1526%2FHrolog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MMZK1526","download_url":"https://codeload.github.com/MMZK1526/Hrolog/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239680989,"owners_count":19679509,"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":["functional-programming","haskell","interpreter","prolog"],"created_at":"2024-11-07T19:38:26.136Z","updated_at":"2025-12-14T10:30:17.188Z","avatar_url":"https://github.com/MMZK1526.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hrolog\n\n## Introduction\nHrolog is a [logic programming language](https://en.wikipedia.org/wiki/Logic_programming) that highly resembles [Prolog](https://en.wikipedia.org/wiki/Prolog). It will support both SLDNF-deduction and abduction as well as some logic-based learning algorithms. In the future, it may also support a Clingo-like Answer Set Programming semantics.\n\nNote that Hrolog is NOT Prolog: they have different syntaxes, and Hrolog will only implement a subset of Prolog specification while adding some unique features.\n\nA simple example of using the CLI is [here](#quick-example). Check out [here](/src/Test/programs/) for more Hrolog examples.\n\nIf you discover any bugs or have any suggestions, please feel free to open an issue or contact me.\n\n## Quick Example\nUse `cabal run Hrolog` to start the interactive shell.\n\nOnce inside, you can load a Hrolog program with `:l \u003cfile_name\u003e`. For example, the following instruction loads the example program [simpleNumbers.hrolog](/src/Test/programs/simpleNumbers.hrolog):\n```\n\u003e :l src/Test/programs/simpleNumbers.hrolog\nProgram src/Test/programs/simpleNumbers.hrolog loaded:\nsucc(1, 0).\nsucc(2, 1).\nsucc(3, 2).\ngt(X, Y) \u003c- succ(X, Y).\ngt(X, Y) \u003c- succ(X, Z), gt(Z, Y).\n\n```\nThen you can query the program with `\u003c- \u003cquery\u003e`. For example, the following query asks for a number greater than 1:\n```\n\u003c- gt(X, 1).\n\nSolution:\nX = 2;\n\nEnter ';' to look for the next solution.\n```\n\nIt finds a solution `X = 2`. You can press `;` to look for the next solution:\n```\n\u003e ;\n\nSolution:\nX = 3;\n\nEnter ';' to look for the next solution.\n\u003e ;\nNo more solutions.\n```\n\nSince we only defined the numbers 0, 1, 2, and 3, it cannot find any number greater than 3:\n```\n\u003e gt(X, 3). # Note that the `\u003c-` can be omitted. Also, the `#` starts a comment, which is legal even in one-liner queries.\nNo solution.\n```\n\nSee the [Syntax](#syntax) section for more details on the syntax of Hrolog, both in the program and in the query.\n\nFinally, you can quit the REPL with `:q`.\n\n## Syntax\nThis section covers the syntax of Hrolog's program, query, and REPL.\n\nIt only covers the syntax for *deduction*. In the future I will add *abduction* syntax.\n\n### Program\n\nThe syntax of Hrolog is similar to that of Prolog, but with several variations and limitations.\n1. In Hrolog, we use `\u003c-` instead of `:-` to delimit the head and body of a clause.\n2. Hrolog does not support variables starting with `_`.\n3. The negation syntax in Hrolog is `!` instead of `\\+`.\n4. Hrolog can contain constraints, namely a clause with no head. For example, `\u003c- a.` is a valid clause in Hrolog. However constraints are currently ignored by the interpreter.\n5. Hrolog does not allow the usage of undeclared predicates and functions. Constants can be used without declaration.\n6. Hrolog's inline comments start with `#` (compare to `%` in Prolog) and end with the end of the line. Hrolog does not have block comments.\n7. Hrolog does not have built-in operators, lists, and tuples. However, they can be defined in a prefix manner. See [here](/src/Test/programs/peanoNumbers.hrolog) for an example of addition and subtraction.\n8. Due to the lack of operators in Hrolog, digital constants does not have special meanings. They are treated as normal constants. For example, `0` is a constant, not a number.\n\nA Hrolog program consists of **clauses**, which consists of at most one **head** and zero or more **bodies**. Each of the heads and bodies is a **term**. There are three types.\n1. **Fact**: a fact is a clause with one head and no body. Its syntax is `\u003cterm\u003e .` For example, `a.` is a fact. The semantics is that `a` is true.\n2. **Rule**: a rule is a clause with one head and one or more bodies. Its syntax is `\u003cterm\u003e \u003c- \u003cterm\u003e [, \u003cterm\u003e]* .` For example, `a \u003c- b, c.` is a rule. The semantics is that `a` is true if `b` and `c` are true.\n3. **Constraint**: a constraint is a clause with no head and one or more bodies. Its syntax is `\u003c- \u003cterm\u003e [, \u003cterm\u003e]* .` For example, `\u003c- a, b.` is a constraint. Currently constraints are ignored by the interpreter.\n\nIn the examples above, all terms are literals. We can also introduce predicates, which describes the relationship between terms. For example, `father(anakin, luke)` is a predicate term. Here, `father` is the **predicate symbol**, and `anakin` and `luke` are the **arguments**. It could have a semantic meaning of \"Anakin is the father of Luke\".\n\nWe use names starting with lowercase letters or digits for predicate symbols and arguments, this is to differentiate between **variables** which starts with uppercase letters. Informally speaking, if a variable appears in the head, it represents any possible value; if it appears in the body, it represents the \"existence\" of a value that satisfies the body.\nFor example, `father(X, luke).` means \"Anyone is the father of Luke\", while `son(luke, X) \u003c- father(X, luke).` means \"If Luke has a father, then Luke is the son of that father\".\n\nWith this, we could build somewhat meaningful rules such as:\n```\nfather(anakin, luke).\nfather(anakin, leia).\nmother(shmi, anakin).\n\nancestor(X, Y) \u003c- father(X, Y).\nancestor(X, Y) \u003c- mother(X, Y).\nancestor(X, Y) \u003c- father(X, Z), ancestor(Z, Y).\nancestor(X, Y) \u003c- mother(X, Z), ancestor(Z, Y).\n```\n\nSemantically, it first gives three examples of parenthood. Then it introduces rules for the predicate `ancestor`.\n\nNote that literals are considered as special predicates that has zero arguments. Therefore, the literal `a` can also be written as `a()`.\n\nThe arguments to predicates can also be function terms. For example, the following program defines addition between Peano numbers:\n```\nadd(0, Y, Y).\nadd(s(X), Y, s(Z)) \u003c- add(X, Y, Z).\n```\n\nHere `s(X)` means the successor of `X`. Therefore, `s(s(0))` represents the number 2. The semantics of the program is that `add(X, Y, Z)` is true if `Z` is the sum of `X` and `Y`. For example, we can query for the result of 2 + 3 by `\u003c- add(s(s(0)), s(s(s(0))), X).` and it will return `X = s(s(s(s(s(0)))))`.\n\n### Query\nA **query** is a special type of clause that has no head. It has the same syntax as a constraint, namely `\u003c- \u003cterm\u003e [, \u003cterm\u003e]* .` except that `\u003c-` can be omitted. For example, `\u003c- a.` is a query. The semantics is that it is asking whether `a` is true.\n\nLet's look at the ancestor example again (with some additional rules):\n```\nfather(anakin, luke).\nfather(anakin, leia).\nmother(shmi, anakin).\n\nancestor(X, Y) \u003c- father(X, Y).\nancestor(X, Y) \u003c- mother(X, Y).\nancestor(X, Y) \u003c- father(X, Z), ancestor(Z, Y).\nancestor(X, Y) \u003c- mother(X, Z), ancestor(Z, Y).\n\nnotAncestor(X, Y) \u003c- !ancestor(X, Y).\n```\n\nHere, if we query `\u003c- ancestor(shmi, luke)`, it will return \"Valid\". If we query `\u003c- ancestor(anakin, X)`. It will return `X = luke` and (on the second search) `X = leia`.\n\nWe can also have a query with multiple bodies. For example, `\u003c- ancestor(X, Y), ancestor(Y, luke).` is looking for an ancestor of `luke` as well as an ancestor of ancestor of `luke`. It will return `X = shmi` and `Y = anakin`.\n\nFinally, we can also build queries around the negation operator `!`. For example, `\u003c- notAncestor(anakin, shmi).` will return `Valid`.\n\n### REPL\nCommand            | Shorthand        | Description\n------------------ | ---------------- | ---------------------------------\n`:load \u003cfilename\u003e` | `:l  \u003cfilename\u003e` | Load the program from the file.\n`:reload`          | `:r`             | Reload the program from the file.\n`\u003c- \u003cquery\u003e`       | `\u003cquery\u003e`        | Query the program with the query.\n`:help`            | `:h`             | Show the help message.\n`:quit`            | `:q`             | Quit the REPL.\n`:set \u003csetting\u003e`   | `:s \u003csetting\u003e`   | Set the setting. See below for details.\n\n`\u003csetting\u003e: [(+|-) \u003csettingName\u003e]+`\n\nSetting Name | Description\n------------ | -----------\n`oneAnswer`  | Only compute one answer for each query. Default is `false`.\n`showSteps`  | Show each step of the evaluation. Default is `false`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmzk1526%2Fhrolog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmmzk1526%2Fhrolog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmzk1526%2Fhrolog/lists"}