{"id":32143323,"url":"https://github.com/kyouko-taiga/logickit","last_synced_at":"2025-10-21T07:57:31.415Z","repository":{"id":63916273,"uuid":"114682450","full_name":"kyouko-taiga/LogicKit","owner":"kyouko-taiga","description":"A Prolog-like language as a Swift Embedded Domain Specific Language.","archived":false,"fork":false,"pushed_at":"2021-08-12T08:08:04.000Z","size":110,"stargazers_count":63,"open_issues_count":1,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-11T05:35:41.561Z","etag":null,"topics":["domain-specific-language","logic-programming"],"latest_commit_sha":null,"homepage":null,"language":"Swift","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/kyouko-taiga.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2017-12-18T20:00:18.000Z","updated_at":"2025-10-02T20:52:15.000Z","dependencies_parsed_at":"2023-01-14T13:45:13.864Z","dependency_job_id":null,"html_url":"https://github.com/kyouko-taiga/LogicKit","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/kyouko-taiga/LogicKit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyouko-taiga%2FLogicKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyouko-taiga%2FLogicKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyouko-taiga%2FLogicKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyouko-taiga%2FLogicKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kyouko-taiga","download_url":"https://codeload.github.com/kyouko-taiga/LogicKit/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyouko-taiga%2FLogicKit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280225808,"owners_count":26293888,"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","status":"online","status_checked_at":"2025-10-21T02:00:06.614Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["domain-specific-language","logic-programming"],"created_at":"2025-10-21T07:57:30.156Z","updated_at":"2025-10-21T07:57:31.401Z","avatar_url":"https://github.com/kyouko-taiga.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LogicKit\n\n[![Build Status](https://travis-ci.org/kyouko-taiga/LogicKit.svg?branch=master)](https://travis-ci.org/kyouko-taiga/LogicKit)\n\nLogicKit is a Prolog-like language, distributed in the form of a Swift Embedded Domain Specific Language (EDSL).\n\nShort paper: [LogicKit: bringing logic programming to swift](https://dl.acm.org/doi/abs/10.1145/3397537.3399575)\n\n## Motivation\n\n[Prolog](https://en.wikipedia.org/wiki/Prolog) is a general purpose logic programming language.\nA program is expressed in terms of relations, and computation in terms of queries over these relations.\nThe beauty of logic programming is that we no longer have to tell a computer *how* to compute a result, but only describe the constraints it should respect.\nFor instance, the following Prolog snippet finds all the pairs of operands whose sum is 2.\n\n```prolog\nadd(zero, Y, Y).\nadd(succ(X), Y, Z) :-\n  add(X, succ(Y), Z).\n\n?- add(X, Y, succ(succ(zero))).\n```\n\nWriting programs this way is arguably quite interesting.\nHowever, just as any other paradigm, logic programming isn't a fit-them-all solution.\nFor instance, algorithms that are easily expressed in an imperative way often prove to be difficult to write in a functional logic programming style.\nThis is why most modern programming languages, like Swift, are all about miying paradigms.\n\nSo why not bringing logic programming into the mix as well!\nWith LogicKit, the above Prolog example can be rewritten entirely in Swift:\n\n```swift\nlet zero: Term = \"zero\"\nlet x: Term = .var(\"x\")\nlet y: Term = .var(\"y\")\nlet z: Term = .var(\"z\")\n\nlet kb: KnowledgeBase = [\n   .fact(\"add\", zero, y, y),\n   .fact(\"add\", .fact(\"succ\", x), y, z) |-\n     .fact(\"add\", x, .fact(\"succ\", y), z),\n]\n\nvar answers = kb.ask(.fact(\"add\", x, y, .fact(\"succ\", .fact(\"succ\", zero))))\nfor result in answers.prefix(3) {\n  print(result)\n}\n```\n\n## Getting Started\n\nThe following is a quick *Getting Started* introduction the installation and use of LogicKit that only brushes over the library.\nYou may refer want to refer to the *User Manual* for more details.\n\n### Quick tutorial\n\nLike Prolog, LogicKit revolves around a knowledge base (or database), against which one can make queries.\nThere are four constructs in LogicKit:\n* facts (`Term.fact(_:_:)`) denote predicates and propositions,\n* rules (`Term.rule(_:_:_:)`) denote conditional facts,\n* literals (`Term.lit(_:)`) that denote atomic values, and\n* variables (`Term.var(_:)`) that act as placeholders for other terms.\n\nKnowledge bases are nothing more than a collection of such constructs:\n\n```swift\nlet kb: KnowledgeBase = [\n  .fact(\"is effective against\", .fact(\"water\"), .fact(\"fire\")),\n  .fact(\"is effective against\", .fact(\"fire\"), .fact(\"grass\")),\n  .fact(\"is effective against\", .fact(\"grass\"), .fact(\"water\")),\n\n  .fact(\"has type\", .fact(\"Bulbasaur\"), .fact(\"grass\")),\n  .fact(\"has type\", .fact(\"Squirtle\"), .fact(\"water\")),\n  .fact(\"has type\", .fact(\"Charmander\"), .fact(\"fire\")),\n]\n```\n\nThe above knowledge base only makes use of facts and propositions.\nIt states for instance that *water is effective against fire*, or that *Squirtle has type water*.\nOne can query such knowledge base as follows:\n\n```swift\nvar answers = kb.ask(.fact(\"has type\", .fact(\"Squirtle\"), .fact(\"water\")))\n```\n\nSince there might be several answers to a single query, `Knowledge.ask(_:logger:)` doesn't return a single yes/no answer.\nInstead, it returns a sequence whose each element denote one correct answer.\nIf the sequence is empty, then there isn't any solution.\n\n```swift\nprint(\"Squirtle has type water:\", answers.next() != nil)\n// Prints \"Squirtle has type water: true\"\n```\n\nBeing able to query our knowledge base this way is nice, but only gets us so far.\nWhat's more interesting is to use LogicKit to make deductions.\nLet's add a rule to our knowledge base:\n\n```swift\n.rule(\"is stronger\", .var(\"x\"), .var(\"y\")) {\n  .fact(\"has type\", .var(\"x\"), .var(\"tx\")) \u0026\u0026\n  .fact(\"has type\", .var(\"y\"), .var(\"ty\")) \u0026\u0026\n  .fact(\"is effective against\", .var(\"tx\"), .var(\"ty\"))\n}\n```\n\nThis rule states that a Pokemon `x` is stronger than a Pokemon `y` if the type of `x` is effective against that of `y`.\nNow we can ask things like:\n\n```swift\nvar answers = kb.ask(.fact(\"is stronger\", .fact(\"Charmander\"), .fact(\"Bulbasaur\")))\n```\n\nor even more interestingly:\n\n```swift\nvar answers = kb.ask(.fact(\"is stronger\", .var(\"a\"), .var(\"b\")))\n```\n\nNote that because the query involves variables, not only are we interested to know if it is satisfiable, but also for what binding of `a` and `b`.\nWell, in fact each element of the sequence returned by `Knowledge.ask(_:logger:)` denotes such binding:\n\n```swift\nfor binding in answers {\n  let a = binding[\"a\"]!\n  let b = binding[\"b\"]!\n  print(\"\\(a) is stronger than \\(b)\")\n}\n// Prints \"Bulbasaur is stronger than Squirtle\"\n// Prints \"Squirtle is stronger than Charmander\"\n// Prints \"Charmander is stronger than Bulbasaur\"\n```\n\nNote that since LogicKit is an EDSL,\nnothing prevents us from using the full power of Swift to make our definitions more readable:\n\n```swift\nlet bulbasaur: Term = \"Bulbasaur\"\nlet squirtle: Term = \"Squirtle\"\nlet charmander: Term = \"Charmander\"\n\ninfix operator !\u003e\nfunc !\u003e(lhs: Term, rhs: Term) -\u003e Term {\n  return .fact(\"is stronger\", lhs, rhs)\n}\n\nlet kb: KnowledgeBase = [\n  bulbasaur  !\u003e squirtle,\n  squirtle   !\u003e charmander,\n  charmander !\u003e bulbasaur,\n]\n\nvar answers = kb.ask(bulbasaur !\u003e squirtle)\n```\n\nLogicKit offers a bunch of syntax sugars to improve the legibility of your code.\nMake sure to check the *User Manual* for a comprehensive documentation.\n\n### Builtins types\n\nHere a list of the builtins types you can use directly in LogicKit:\n\n|Builtins types|Constructor|Operators|Helpers|\n|---|-----------|---------|---------|\n|**Nat**|`zero succ(_:)`|`add(_:_:_:)`, `sub(_:_:_:)`, `mul(_:_:_:)` \u003cbr/\u003e `div(_:_:_:)`, `mod(_:_:_:)` \u003cbr/\u003e `greater(_:_:)`, `greaterOrEqual(_:_:)` \u003cbr/\u003e `smaller(_:_:)`, `smallerOrEqual(_:_:)`| `Nat.from(_:)` \u003cbr/\u003e `asSwiftInt(_:)` \u003cbr/\u003e `isNat(_:)`|\n|**List**|`empty cons(_:_:)`|`count(list:count:)` \u003cbr/\u003e `contains(list:element:)` \u003cbr/\u003e `concat(_:_:_:)`|`List.from\u003cCollection\u003e(elements:)` \u003cbr/\u003e `isList(_:)`|\n\nExample on how to use `List.from`:\n\n```swift\nlet list = List.from(elements: [1,2,3].map(Nat.from))\n// Or\nlet list = List.from(elements: [Nat.from(1), Nat.from(2), Nat.from(3)])\n```\n\n### Native predicates\n\nNative predicates are an experimental feature that allows Swift functions to act as logic predicates.\nWhile they cannot be used to infer the value of a logic variable, they can be used to check if a particular binding satisfies some properties.\nA common pattern is to use native predicates to define the body of a rule, so that it can be defined in terms of a Swift predicate:\n\n```swift\nlet isTextOutputStream = \"isTextOutputStream\"/1\nlet a: Term = .var(\"a\")\nlet kb: KnowledgeBase = [\n  isTextOutputStream(a) |- .native { t in\n    t[\"a\"]?.extractValue() is TextOutputStream\n  }\n]\n```\n\n### Installation\n\nLogicKit is distributed in the form of a Swift package and can be integrated with the [Swift Package Manager](https://swift.org/package-manager/).\n\nStart by creating a new package (unless you already have one):\n\n```bash\nmkdir MyLogicProgram\ncd MyLogicProgram\nswift package init --type executable\n```\n\nThen add LogicKit as a dependency to your package, from your `Package.swift` file:\n\n```swift\nimport PackageDescription\n\nlet package = Package(\n  name: \"MyLogicProgram\",\n  dependencies: [\n    .package(url: \"https://github.com/kyouko-taiga/LogicKit\", .branch(\"master\")),\n  ],\n  targets: [\n    .target(name: \"MyLogicProgram\", dependencies: [\"LogicKit\"]),\n  ]\n)\n```\n\n\u003e The master branch of the LogicKit always refers to the latest stable version of LogicKit, so using `.branch(\"master\")` to specify the dependency location guarantees you'll always pull the latest version. See Swift Package Manager's documentation for alternative configurations.\n\nMake sure the Swift Package Manager is able to properly download, compile and link LogicKit with the following command:\n\n```bash\nswift build\n```\n\nIf everything goes well, you should then be able to import LogicKit in your own Swift sources:\n\n```swift\nimport LogicKit\n\n// Your code here ...\n```\n\n\u003e For Xcode users:\n\u003e You can use the Swift Package Manager to create an Xcode project.\n\u003e Once you've added LogicKit has a dependency and compiled your project at least once, type the command:\n\u003e\n\u003e ```bash\n\u003e swift package generate-xcodeproj\n\u003e ```\n\u003e\n\u003e It will create a `MyLogicProgram.xcodeproj` directory you can edit with Xcode.\n\u003e The schemes of the auto-generated package might require some manual configuration.\n\u003e Please refer to Xcode's documentation for more information on that end.\n\n## License\n\nLogicKit is licensed under the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyouko-taiga%2Flogickit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkyouko-taiga%2Flogickit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyouko-taiga%2Flogickit/lists"}