{"id":32160342,"url":"https://github.com/ivanbakel/hout-prover","last_synced_at":"2026-02-22T11:03:35.101Z","repository":{"id":62436189,"uuid":"254359278","full_name":"ivanbakel/hout-prover","owner":"ivanbakel","description":"A non-interactive proof assistant using the Haskell type system","archived":false,"fork":false,"pushed_at":"2020-04-11T22:11:05.000Z","size":26,"stargazers_count":38,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-10-21T13:40:51.250Z","etag":null,"topics":["curry-howard-isomorphism","monad","proof-assistant"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ivanbakel.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":"2020-04-09T12:00:28.000Z","updated_at":"2025-09-20T19:20:39.000Z","dependencies_parsed_at":"2022-11-01T21:16:52.814Z","dependency_job_id":null,"html_url":"https://github.com/ivanbakel/hout-prover","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ivanbakel/hout-prover","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivanbakel%2Fhout-prover","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivanbakel%2Fhout-prover/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivanbakel%2Fhout-prover/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivanbakel%2Fhout-prover/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ivanbakel","download_url":"https://codeload.github.com/ivanbakel/hout-prover/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivanbakel%2Fhout-prover/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29710317,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T10:34:24.778Z","status":"ssl_error","status_checked_at":"2026-02-22T10:32:23.200Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["curry-howard-isomorphism","monad","proof-assistant"],"created_at":"2025-10-21T13:39:01.781Z","updated_at":"2026-02-22T11:03:35.096Z","avatar_url":"https://github.com/ivanbakel.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# hout - a non-interactive proof assistant for first-order logic, in Haskell [![Hackage](https://img.shields.io/hackage/v/hout)](https://hackage.haskell.org/package/hout)\n\nhout is an in-Haskell non-interactive proof assistant for intuitionistic first-order logic.\n\nAlternatively, hout provides a monad that allows you to write functions in the style of proof-assistant proofs, which are then computable Haskell terms.\n\nThis is possible thanks to the Curry-Howard isomorphism.\n\n## Examples\n\nHave a look at `examples/Hout/Examples.hs` for some examples.\n\n## What?\n\nIf you know about the CHI and intuitionistic logic, skip this section.\n\n### The Curry-Howard isomorphism\n\nThe Curry-Howard isomorphism (or correspondence) is a pattern between intuitionistic logic and type theory, which says that propositions correspond to types, and proofs correspond to terms.\n\nThe basis of this correspondence is that an *inhabitant* of a type is a proof that the type is inhabited. For example, the term `3 :: Int` is a proof that you can construct some terminating value of type `Int`.\n\nWhat about types with no inhabitant? Taking some type known to have no inhabitants, like `Void`, you can show that a type `a` is uninhabited by producing a terminating term of type `a -\u003e Void`. Why? Because `a -\u003e Void` is inhabited only if `a` is uninhabited, and a term of type `a -\u003e Void` is a *proof that `a -\u003e Void` is inhabited*!\n\nThis also has implications for function types - a term with type `a -\u003e b` is a function from terms of type `a` to terms of type `b`. You can equally consider it as a function from proofs of the proposition `a` to proofs of the proposition `b` - in other words, the function itself is a proof that `a` implies `b`, because if you have a proof that `a` is true, you can obtain a proof that `b` is true.\n\nOther logical connectives also have equivalents in Haskell types. `False` is `Void`, because you can't construct a proof for it; `a /\\ b` is the tuple (or product) `(a, b)`; `a \\/ b` is (the sum) `Either a b`; and `Not a` - the claim that `a` is uninhabited - is precisely `a -\u003e False`. `True` can be any inhabited type, but it's helpful to have a type with a canonical construction, so `True` is normally `()`, the empty tuple, which has the unique constructor `()`.\n\nYou can see the correspondence in these types - `(a, b)` is inhabited if and only if both `a` and `b` are inhabited. Similarly, `Either a b` is inhabited if and only if at least one of `a`, `b` is inhabited. Phrasing it in terms of proofs, if you have a proof of `a` and a proof of `b`, you can construct a proof of `a /\\ b` (and vice-versa) - and with a proof of `a`, you can construct a proof of `a \\/ b`. With a proof of `a \\/ b`, you can *destruct* the proof to get either a proof for `a` (`Left a`) or a proof for `b` (`Right b`).\n\nFor notation's sake, we write `a \u003c-\u003e b` for the type `(a -\u003e b) /\\ (b -\u003e a)`.\n\n### Intuistionistic logic\n\nIntuistionistic (or constructive) logic is a subset of classical logic (the kind of logic you normally learn in a CS or Maths course). It behaves exactly like classical logic, but with one caveat - *you can only _construct_ proofs of a proposition*.\n\nTo see what that means, consider the type of the law of the excluded middle - `forall a. a \\/ Not a`. For every type `a`, one of these two terms must be constructable - either `a` is inhabited, so you can construct a value of type `a`, or `a` is uninhabited, so you can construct a function of type `a -\u003e Void`.\n\nBut you can't write a terminating Haskell function with type `forall a. a \\/ Not a` - because it would require you to somehow decide if `a` is inhabited, and then get a value of type `a` if it was. In other words, you have to construct either a `Left a` or a `Right (Not a)`, and you have no way to do either of those things.\n\nThere are lots of other consequences of this caveat: the following implications do *not* hold in intuitionistic logic - and similarly, you cannot write a terminating Haskell term for their type.\n\n  * `Not (Not a) -\u003e a`\n  * `(a -\u003e b) -\u003e (Not a \\/ b)`\n  * `Not (Not a /\\ Not b) -\u003e a \\/ b`\n\n## Proofs and the Tactic monad\n\nThe `Tactic` monad is an indexed monad for which the monad state is the current proof goal, and the type argument is an additional hypothesis introduced at that proof step. Looking at its definition\n```\ndata Tactic from to a = Tactic ((a -\u003e to) -\u003e from)\n```\nA `Tactic` term represents a valid goal transformation - you are allowed to change a proof of `from` into a proof of `to`, and introduce the additional hypothesis `a`, if you can use a proof of `a -\u003e to` to prove `from`.\n\nFor example, the `apply` function has the signature\n```\napply :: (a -\u003e b) -\u003e Tactic b a ()\n```\nGiven a function `a -\u003e b`, it allows you to transform the goal from proving `b` to proving `a` - because once you prove `a`, it will be possible to use the given function to produce a proof of `b`.\n\nSome tactics introduce additional hypotheses - such as `intro`\n```\nintro :: Tactic (a -\u003e b) b a\n```\n`intro` allows you to transform a goal of `a -\u003e b` to a goal of `b`, giving you the hypothesis of type `a` to bind into a variable. If you can use the proof of `a` to construct a proof of `b`, then the resulting function term is indeed a proof of `a -\u003e b`.\n\n### Available tactics\n\nhout provides some tactics based on those used in `Coq` - for example, you can `apply` hypotheses to a goal; you can `split` the proof a conjunction into proofs of its conjuncts; you can `intro` a variable; you can `exists` the witness of an existential goal; you can `rewrite` propositions with equality; you can even `assert` hypothesis and produce subgoals.\n\nThe full list of tactics is given in `Hout.Prover.Tactics`, and it is possible to write your own using the type signature of the `Tactic` monad.\n\n### Proofs in do notation\n\nBecause `Tactic` is an indexed monad, you can use the `do-notation` package to write proofs in do notation, which end up looking quite similar to proofs in interactive proof assistants. Some advice for doing this is:\n\n  * use pattern-matching in binds, particularly when working with existential types. GHC has some unfortunate behaviour when trying to use `let` in do notation when working with existential type arguments.\n  * Enable block arguments, and use do notation for subgoals\n  * If your final statement is a tactic that introduces a hypothesis, but the new goal is trivial `()`, use `qed` to end your proof.\n\n### Limitations\n\nThe use of `Forall` is limited by Haskell's lack of support for impredicative polymorphism - the instantiation of type variables with higher-ranked types. This makes it basically impossible to prove a `Forall` using the `Tactic` monad, since under the hood `Forall` is just a Haskell type-level `forall`.\n\n## Computations written in the proof style\n\nhout also has the nice property of intuitionistic proof assistants that proofs are themselves terms, and can be run as Haskell code. This gives hout the alternative use of writing functions in a proof-y syntax using the `Tactic` monad. For example, the `identity` function can be written as\n```\nidentity :: a -\u003e a\nidentity :: runProof $ Proof do\n  a \u003c- intro\n  exact a\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivanbakel%2Fhout-prover","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivanbakel%2Fhout-prover","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivanbakel%2Fhout-prover/lists"}