{"id":13995927,"url":"https://github.com/rntz/datafun","last_synced_at":"2026-02-21T12:03:40.963Z","repository":{"id":2452896,"uuid":"46583808","full_name":"rntz/datafun","owner":"rntz","description":"Research on integrating datalog \u0026 lambda calculus via monotonicity types","archived":false,"fork":false,"pushed_at":"2022-06-21T12:57:02.000Z","size":2780,"stargazers_count":384,"open_issues_count":2,"forks_count":15,"subscribers_count":43,"default_branch":"master","last_synced_at":"2024-08-10T14:21:49.444Z","etag":null,"topics":["compiler","datalog","monotonicity","programming-language","query","semilattices","type-theory"],"latest_commit_sha":null,"homepage":"http://www.rntz.net/datafun/","language":"TeX","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rntz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-20T20:00:30.000Z","updated_at":"2024-07-10T16:08:09.000Z","dependencies_parsed_at":"2022-07-14T23:17:01.278Z","dependency_job_id":null,"html_url":"https://github.com/rntz/datafun","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/rntz%2Fdatafun","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rntz%2Fdatafun/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rntz%2Fdatafun/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rntz%2Fdatafun/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rntz","download_url":"https://codeload.github.com/rntz/datafun/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227190515,"owners_count":17745277,"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":["compiler","datalog","monotonicity","programming-language","query","semilattices","type-theory"],"created_at":"2024-08-09T14:03:40.165Z","updated_at":"2026-02-21T12:03:35.929Z","avatar_url":"https://github.com/rntz.png","language":"TeX","readme":"# FILES\n\n`paper/`: ICFP 2016 paper.\n\n`src/`: Implementation of Datafun in Racket. `src/repl.rkt` is most useful.\n\nWhat follows is an *extremely* out-of-date description of Datafun's type theory.\nFor more up-to-date information,\n[here's a paper preprint](http://www.rntz.net/files/datafun.pdf); or you can\nclone the repository and run `make` in the `paper/` directory to produce\n`datafun.pdf`.\n\n# Datafun\n\n    poset types     A,B ::= bool | nat | A × B | A → B | A →⁺ B | Set A | A + B\n    lattice types   L,M ::= bool | nat | L × M | A → L | A →⁺ L | Set A\n    expressions     e   ::= x | λx.e | e e\n                          | (e, e) | πᵢ e\n                          | true | false | if e then e else e\n                          | inᵢ e | case e of in₁ x → e; in₂ x → e\n                          | ∅ | e ∨ e | {e} | ⋁(x ∈ e) e\n                          | fix x. e\n\n    contexts        Δ   ::= · | Δ,x:A\n    monotone ctxts  Γ   ::= · | Γ,x:A\n\n## Semantic intuition\n\nTypes correspond to *partially ordered sets* (posets):\n\n- `bool` is booleans; `false` \u003c `true`.\n\n- `nat` is the naturals, ordered 0 \u003c 1 \u003c 2 \u003c ...\n\n- `A × B` is pairs, ordered pointwise:\n  `(a₁,b₁) ≤ (a₂,b₂)` iff `a₁ ≤ a₂` and `b₁ ≤ b₂`.\n\n- `A + B` is sums, ordered disjointly. `in₁ a₁ ≤ in₁ a₂` iff `a₁ ≤ a₂`, and\n  likewise for `in₂`; but `in₁ a` and `in₂ b` are not comparable to one another.\n\n- `Set A` is *finite* sets of `A`s, ordered by inclusion:\n  `x ≤ y` iff `∀(a ∈ x) a ∈ y`.\n\n- `A → B` are functions, ordered pointwise: `f ≤ g` iff `∀(x : B) f x ≤ g x`.\n\n- `A →⁺ B` are *monotone* functions; for any `f : A →⁺ B`, given `x,y : A` such\n  that `x ≤ y` we know that `f x ≤ f y`. The type system enforces this\n  monotonicity. Monotone functions are ordered pointwise, just like regular\n  functions.\n\nLattice types `L` are a subset of all types, defined so that every lattice type\nhappens to be *unital semilattices* (usls) — that is, join-semilattices with a\nleast element. Any lattice type is a type, but not all types are lattice types.\n\nSemantics of expressions, in brief:\n\n- `x`, `(e₁, e₂)`, `πᵢ e`, `inᵢ e`, `if`, `true`, `false`, and `case` all do\n  what you'd expect.\n\n- `λx.e` and `e e` both do what you'd expect. However, it is left ambiguous\n  whether they represent ordinary or monotone function creation/application.\n\n  One could of course require the programmer to write ordinary and monotone\n  functions differently (or even ordinary and monotone function *applications*\n  differently). But for our purposes it's simplest to just give two typing rules\n  (ordinary and monotone) for `λx.e` (and likewise `e e`).\n\n  It is definitely possible to infer monotonicity in a bidirectional way, and\n  possibly even in a Damas-Milner-ish way, but that's outside the scope of this\n  README.\n\n- `∅` represents the least element of a lattice type.\n\n- `e₁ ∨ e₂` represents the least upper bound (\"lattice join\") of `e₁` and `e₂`.\n\n- `{e}` represents the singleton set containing `e`.\n\n- `⋁(x ∈ e₁) e₂` is set-comprehension. `e₁` must have a finite set type; `e₂`\n  must have a lattice type. For each `x` in `e₁`, we compute `e₂`; then we\n  lattice-join together all values of `e₂` computed this way, and that is our\n  result. This generalizes the \"bind\" operation of the finite-set monad.\n\n- `fix x. e` finds the least fixed-point of the monotone function `λx. e`.\n\n## Typing judgment: `Δ;Γ ⊢ e : A`\n\nOur typing judgment is `Δ;Γ ⊢ e : A`\n\nWe call `Δ` our *unrestricted* context and `Γ` our *monotone* context. Both\ncontexts obey the usual intuitionistic structural rules (weakening, exchange).\n\n### Typing rules\n\n     Δ,x:A; Γ ⊢ e : B       Δ;Γ ⊢ e₁ : A → B   Δ;· ⊢ e₂ : A\n    ------------------ λ    -------------------------------- app\n    Δ;Γ ⊢ λx.e : A → B             Δ;Γ ⊢ e₁ e₂ : B\n\n     Δ; Γ,x:A ⊢ e : B       Δ;Γ ⊢ e₁ : A →⁺ B   Δ;Γ ⊢ e₂ : A\n    ------------------- λ⁺  --------------------------------- app⁺\n    Δ;Γ ⊢ λx.e : A →⁺ B            Δ;Γ ⊢ e₁ e₂ : B\n\nNB. The monotone context of `e₂` in the rule `app` for applying ordinary\nfunctions must be empty! Since `A → B` represents an *arbitrary* function, we\ncannot rely on its output being monotone in its argument. Thus its argument must\nbe, not *monotone* in Γ, but *constant*.\n\nThe typing rules for tuples, sums, and booleans are *mostly* boring:\n\n        Δ;Γ ⊢ eᵢ : Aᵢ            Δ;Γ ⊢ e : A₁ × A₂\n    -----------------------      ------------------\n    Δ;Γ ⊢ (e₁,e₂) : A₁ × A₂       Δ;Γ ⊢ πᵢ e : Aᵢ\n\n                                           Δ;Γ ⊢ e : bool    Δ;Γ ⊢ eᵢ : A\n    -----------------  ------------------  -------------------------------\n    Δ;Γ ⊢ true : bool  Δ;Γ ⊢ false : bool  Δ;Γ ⊢ if e then e₁ else e₂ : A\n\n        Δ;Γ ⊢ e : Aᵢ\n    ---------------------\n    Δ;Γ ⊢ inᵢ e : A₁ + A₂\n\nHowever, there are *two* eliminators for sum types:\n\nTODO\n\nThe typing rules get more interesting now:\n\n                     Δ;Γ ⊢ eᵢ : L\n    -----------    -----------------\n    Δ;Γ ⊢ ∅ : L    Δ;Γ ⊢ e₁ ∨ e₂ : L\n\n      Δ;· ⊢ e : A        Δ;Γ ⊢ e₁ : Set A  Δ,x:A; Γ ⊢ e₂ : L\n    -----------------    ------------------------------------\n    Δ;Γ ⊢ {e} : Set A          Δ;Γ ⊢ ⋁(x ∈ e₁) e₂ : L\n\n    Δ; Γ,x:L ⊢ e : L   L equality\n    ----------------------------- fix\n          Δ;Γ ⊢ fix x.e : L\n\nIn the last rule, for `fix`, the premise `L equality` means that the type `L` at\nwhich the fixed-point is computed must have decidable equality.\n\n# Two-layer formulation\nAlternative, two-layer formulation:\n\n    set types       A,B ::= U P | A ⊗ B | A ⊕ B | A ⊃ B\n    poset types     P,Q ::= bool | nat | P × Q | P →⁺ Q | Set A\n                          | Disc A | P + Q\n    lattice types   L,M ::= bool | nat | L × M | P →⁺ M | Set A\n    expressions     e   ::= x | λx.e | e e | (e, e) | πᵢ e\n                          | inᵢ e | case e of in₁ x → e; in₂ x → e\n                          | U u\n    lattice exprs   u   ::= x | λx.u | u u | (u, u) | πᵢ u\n                          | ∅ | u ∨ u | {e} | ⋁(x ∈ u) u\n                          | fix x. u\n                          | D e | U⁻¹ e | let D x = u in u\n\n    Δ;· ⊢ u : P               Δ ⊢ e : U P\n    ------------- U         --------------- U⁻¹\n    Δ ⊢ U u : U P           Δ;Γ ⊢ U⁻¹ e : P\n\n      Δ ⊢ e : A             Δ;Γ ⊢ u₁ : D A   Δ,x:A; Γ ⊢ u₂ : P\n    --------------- D       ----------------------------------- let-D\n    Δ;Γ ⊢ D e : D A            Δ;Γ ⊢ let D x = u₁ in u₂ : P\n\nI use `⊗` and `⊕` for set types not because they are linear, but simply to\ndistinguish them from the `×` and `+` operations on *poset* types.\n\nThis version needs to be fleshed out more fully. In particular, we need some\naxioms to ensure that `U (P + Q) = U P ⊕ U Q`.\n","funding_links":[],"categories":["TeX"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frntz%2Fdatafun","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frntz%2Fdatafun","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frntz%2Fdatafun/lists"}