diff --git a/README.md b/README.md
index f337b0570..9d15dee80 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
An experimental proof assistant for synthetic ∞-categories.
-[](https://fizruk.github.io/rzk/)
+[](https://fizruk.github.io/rzk/)
## About this project
diff --git a/docs/docs/related/sHoTT.md b/docs/docs/related/sHoTT.md
index aecbb113d..029732444 100644
--- a/docs/docs/related/sHoTT.md
+++ b/docs/docs/related/sHoTT.md
@@ -1,11 +1,11 @@
# sHoTT
-[sHoTT](https://github.com/fizruk/sHoTT) is a formalisation project for simplicial HoTT and ∞-categories.
+sHoTT is a formalisation project for simplicial HoTT and ∞-categories.
-The project is a fork of https://github.com/emilyriehl/yoneda,
+The project is a fork of https://github.com/emilyriehl/yoneda ,
with a goal to grow and eventually include various
formalisations for HoTT (e.g. HoTT book),
-synthetic fibered ∞-categories from the work of Ulrich Buchholtz and Jonathan Weinberger, variations of cubical type theories, etc.
+synthetic fibered ∞-categories from the work of Ulrik Buchholtz and Jonathan Weinberger, variations of cubical type theories, etc.
See more details in the documentation of the project at
-[https://github.com/fizruk/sHoTT](https://github.com/fizruk/sHoTT).
+https://github.com/fizruk/sHoTT .
diff --git a/docs/docs/related/simple-topes.md b/docs/docs/related/simple-topes.md
index 9517161b7..651bb04e9 100644
--- a/docs/docs/related/simple-topes.md
+++ b/docs/docs/related/simple-topes.md
@@ -1,6 +1,6 @@
# simple-topes
-[simple-topes](https://github.com/fizruk/simple-topes) is a playground theorem prover project for type theory with shapes that allows user-defined cubes and topes. Once stable, the project will be merged into `rzk`, extending it to a proof assistant for type theory with (user-defined) cubes, topes, and shapes.
+simple-topes is a playground theorem prover project for type theory with shapes that allows user-defined cubes and topes. Once stable, the project will be merged into `rzk`, extending it to a proof assistant for type theory with (user-defined) cubes, topes, and shapes.
See more details in the documentation of the project at
-[https://github.com/fizruk/simple-topes](https://github.com/fizruk/simple-topes).
+https://github.com/fizruk/simple-topes .
diff --git a/docs/docs/rzk-1/introduction.md b/docs/docs/rzk-1/introduction.md
index 8135bfcb8..8cd6fa6ca 100644
--- a/docs/docs/rzk-1/introduction.md
+++ b/docs/docs/rzk-1/introduction.md
@@ -3,7 +3,7 @@
!!! warning "Work-in-progress"
The documentation is not yet up-to-date with all
the changes introduced in `rzk-0.2.0`.
- See [`rzk` changelog](https://github.com/fizruk/rzk/blob/release-v0.2.0/rzk/ChangeLog.md#v020---2022-04-20) for more details.
+ See [`rzk` changelog](https://github.com/fizruk/rzk/blob/release-v0.3.0/rzk/ChangeLog.md#v020---2022-04-20) for more details.
`rzk` is an experimental proof assistant for synthetic ∞-categories.
`rzk-1` is an early version of the language supported by `rzk`.
diff --git a/docs/docs/rzk-1/render.md b/docs/docs/rzk-1/render.md
new file mode 100644
index 000000000..a1d9fd153
--- /dev/null
+++ b/docs/docs/rzk-1/render.md
@@ -0,0 +1,415 @@
+# Rendering Diagrams
+
+Starting from version `0.3.0`, `rzk` supports rendering of topes, types, and terms as diagrams.
+
+This is a literate `rzk` file:
+
+```rzk
+#lang rzk-1
+```
+
+To enable rendering, enable option `"render" = "svg"` (to disable, `"render" = "none"`):
+
+```rzk
+#set-option "render" = "svg" -- enable rendering in SVG
+```
+
+Rendering is completely automatic, and works in the following situations:
+
+1. Mapping from a shape (including curried mappings), up to 3 dimensions, only in products of `2` cubes;
+2. Type of mapping from a shape (including curried mappings), up to 3 dimensions, only in products of `2` cubes.
+3. Mappings from a shape that is a section of an existing shape.
+
+The rendering assigns the following colors:
+
+- purple is assigned for parameters (context) variables;
+- blue is used for fillings for types (e.g. for `hom` and `hom2`);
+- red is used for terms (e.g. `Segal-comp-witness`);
+- orange is used for shapes in the tope layer;
+- grey is used for discarded parts of a (larger) mapping (e.g. when extracting a diagonal/face from a larger shape).
+
+The SVG pictures can be inserted directly into `.md` files before a corresponding `rzk` code block. At the bottom of a markdown file, you might want to add stylization, e.g.:
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Examples
+
+### Visualising Simplicial Topes
+
+Topes are visualised with **orange** color:
+
+
+
+
+
+
+
+
+
+
+ •
+ •
+ •
+
+
+```rzk
+-- 2-simplex
+#def Δ² : (2 * 2) -> TOPE
+ := \(t, s) -> s <= t
+```
+
+Boundary of a tope:
+
+
+
+
+
+
+
+
+ •
+ •
+ •
+
+
+```rzk
+-- boundary of a 2-simplex
+#def ∂Δ² : Δ² -> TOPE
+ := \(t, s) -> s === 0_2 \/ t === 1_2 \/ s === t
+```
+
+The busiest tope diagram involves the entire 3D cube:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ •
+ •
+ •
+ •
+ •
+ •
+ •
+ •
+
+
+```rzk
+-- 3-dim cube
+#def 2³ : (2 * 2 * 2) -> TOPE
+ := \_ -> TOP
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ •
+ •
+ •
+ •
+
+
+```rzk
+-- 3-simplex
+#def Δ³ : (2 * 2 * 2) -> TOPE
+ := \((t1, t2), t3) -> t3 <= t2 /\ t2 <= t1
+```
+
+
+### Visualising Simplicial Types
+
+Types are visualised with **blue** color. Recognised parameter part (e.g. fixed endpoints, edges, faces with clear labels) are visualised with **purple** color. When a type is constructed by taking a part of another shape, the rest of the larger shape is colored using **gray** color.
+
+
+
+
+ x
+ y
+
+
+```rzk
+-- [RS17, Definition 5.1]
+-- The type of arrows in A from x to y.
+#def hom
+ (A : U) -- A type.
+ (x y : A) -- Two points in A.
+ : U -- (hom A x y) is a 1-simplex (an arrow)
+ := (t : 2) -> A [ -- in A where
+ t === 0_2 |-> x, -- * the left endpoint is exactly x
+ t === 1_2 |-> y -- * the right endpoint is exactly y
+ ]
+```
+
+
+
+
+ f
+ f
+ h
+ h
+ g
+ g
+ x
+ y
+ z
+
+
+```rzk
+-- [RS17, Definition 5.2]
+-- the type of commutative triangles in A
+#def hom2
+ (A : U) -- A type.
+ (x y z : A) -- Three points in A.
+ (f : hom A x y) -- An arrow in A from x to y.
+ (g : hom A y z) -- An arrow in A from y to z.
+ (h : hom A x z) -- An arrow in A from x to z.
+ : U -- (hom2 A x y z f g h) is a 2-simplex (triangle)
+ := { (t1, t2) : Δ² } -> A [ -- in A where
+ t2 === 0_2 |-> f t1, -- * the top edge is exactly f,
+ t1 === 1_2 |-> g t2, -- * the right edge is exactly g, and
+ t2 === t1 |-> h t2 -- * the diagonal is exactly h
+ ]
+```
+
+### Visualising Terms of Simplicial Types
+
+Terms (with non-trivial labels) are visualised with **red** color (you can see a detailed label on hover). Recognised parameter part (e.g. fixed endpoints, edges, faces with clear labels) are visualised with **purple** color. When a term is constructed by taking a part of another shape, the rest of the larger shape is colored using **gray** color.
+
+We can visualise terms that fill a shape:
+
+
+ second a (second x₂, first x₂)
+
+ second a (first x₂, second x₂)
+
+ f
+ f
+ f
+ f
+ first a (second (first x₂, second x₂))
+
+ g
+ g
+ g
+ g
+ x
+ y
+ y
+ z
+
+
+```rzk
+#def square
+ (A : U)
+ (x y z : A)
+ (f : hom A x y)
+ (g : hom A y z)
+ (h : hom A x z)
+ (a : Sigma (h' : hom A x z), hom2 A x y z f g h')
+ : (2 * 2) -> A
+ := \(t, s) -> recOR( s <= t |-> second a (t, s) , t <= s |-> second a (s, t))
+```
+
+If a term is extracted as a part of a larger shape, generally, the whole shape will be shown (in gray):
+
+
+ second a x₂
+
+ second a x₂
+
+ second a x₂
+
+ second a x₂
+
+ second a x₂
+
+ second a x₂
+
+ second a x₂
+
+ second a x₂
+
+ first a (second x₂)
+
+ first a (second x₂)
+
+ f
+ f
+ second a x₂
+
+ second a x₂
+
+ second a x₂
+
+ second a x₂
+
+ second a x₂
+
+ second a x₂
+
+ first a (second x₂)
+
+ y
+ y
+ first a (second x₂)
+
+ z
+ z
+ first a (second x₂)
+
+ x
+ y
+ y
+ z
+ y
+ z
+
+
+```rzk
+#def face
+ (A : U)
+ (x y z : A)
+ (f : hom A x y)
+ (a : Sigma (g : hom A y z), {((t1, t2), t3) : 2 * 2 * 2 | t3 <= t1 \/ t2 <= t1} -> A [ t1 === 0_2 |-> f t2, t1 === 1_2 |-> g t3 ])
+ : Δ² -> A
+ := \(t, s) -> second a ((t, t), s)
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml
index 84b15ea60..aa042002e 100644
--- a/docs/mkdocs.yml
+++ b/docs/mkdocs.yml
@@ -4,6 +4,7 @@ nav:
- About: index.md
- rzk-1 Language:
- Introduction: rzk-1/introduction.md
+ - Rendering Diagrams: rzk-1/render.md
- Weak tope disjunction elimination: rzk-1/recId.md
- Tools:
- IDE support: tools/ide.md
diff --git a/images/split-demo-render.png b/images/split-demo-render.png
new file mode 100644
index 000000000..a98b752d6
Binary files /dev/null and b/images/split-demo-render.png differ
diff --git a/rzk/ChangeLog.md b/rzk/ChangeLog.md
index 05543b32c..1f5efdf65 100644
--- a/rzk/ChangeLog.md
+++ b/rzk/ChangeLog.md
@@ -6,6 +6,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to the
[Haskell Package Versioning Policy](https://pvp.haskell.org/).
+## v0.3.0 — 2022-04-28
+
+This version introduces an experimental feature for generating visualisations for simplicial terms in SVG.
+To enable rendering, enable option `"render" = "svg"` (to disable, `"render" = "none"`):
+
+```rzk
+#set-option "render" = "svg" -- enable rendering in SVG
+```
+
+Minor changes:
+
+- Exit with non-zero code upon a type error (see b135c4fb)
+- Fix external links and some typos in the documentation
+
+Fixes:
+
+- Fixed an issue with tope solver when context was empty (see 6196af9e);
+- Fixed #33 (missing coherence check for restricted types).
+
## v0.2.0 - 2022-04-20
This version was a complete rewrite of the proof assistant, using a new parser, a new internal representation, and a rewrite of the typechecking logic. This is still a prototype, but, arguably, significantly more stable and manageable than version 0.1.0.
diff --git a/rzk/debug.txt b/rzk/debug.txt
deleted file mode 100644
index 0755b1c4d..000000000
--- a/rzk/debug.txt
+++ /dev/null
@@ -1,200 +0,0 @@
-Checking module from /Users/nikolaikudasov/git/emilyriehl/yoneda/hott/0-common.rzk
-[ 1 out of 7 ] Checking #def prod
-[ 2 out of 7 ] Checking #def diagonal
-[ 3 out of 7 ] Checking #def composition
-[ 4 out of 7 ] Checking #def triple-composition
-[ 5 out of 7 ] Checking #def identity
-[ 6 out of 7 ] Checking #def constant
-[ 7 out of 7 ] Checking #def reindex
-Checking module from /Users/nikolaikudasov/git/emilyriehl/yoneda/hott/1-contractible.rzk
-[ 1 out of 3 ] Checking #def isContr
-[ 2 out of 3 ] Checking #def contraction-center
-[ 3 out of 3 ] Checking #def contracting-htpy
-Checking module from /Users/nikolaikudasov/git/emilyriehl/yoneda/hott/2-paths.rzk
-[ 1 out of 21 ] Checking #def rev
-[ 2 out of 21 ] Checking #def concat
-[ 3 out of 21 ] Checking #def altconcat
-[ 4 out of 21 ] Checking #def refl-concat
-[ 5 out of 21 ] Checking #def concat-altconcat
-[ 6 out of 21 ] Checking #def altconcat-concat
-[ 7 out of 21 ] Checking #def zig-zag-concat
-[ 8 out of 21 ] Checking #def zag-zig-concat
-[ 9 out of 21 ] Checking #def concat-right-cancel
-[ 10 out of 21 ] Checking #def homotopy-concat
-[ 11 out of 21 ] Checking #def concat-homotopy
-[ 12 out of 21 ] Checking #def alt-triangle-rotation
-[ 13 out of 21 ] Checking #def triangle-rotation
-[ 14 out of 21 ] Checking #def ap
-[ 15 out of 21 ] Checking #def ap-id
-[ 16 out of 21 ] Checking #def ap-htpy
-[ 17 out of 21 ] Checking #def ap-comp
-[ 18 out of 21 ] Checking #def rev-ap-comp
-[ 19 out of 21 ] Checking #def transport
-[ 20 out of 21 ] Checking #def transport2
-[ 21 out of 21 ] Checking #def apd
-Checking module from /Users/nikolaikudasov/git/emilyriehl/yoneda/hott/3-homotopies.rzk
-[ 1 out of 10 ] Checking #def homotopy
-[ 2 out of 10 ] Checking #def homotopy-rev
-[ 3 out of 10 ] Checking #def homotopy-composition
-[ 4 out of 10 ] Checking #def homotopy-postwhisker
-[ 5 out of 10 ] Checking #def homotopy-prewhisker
-[ 6 out of 10 ] Checking #def nat-htpy
-[ 7 out of 10 ] Checking #def a-cylinder-homotopy-coherence
-[ 8 out of 10 ] Checking #def another-cylinder-homotopy-coherence
-[ 9 out of 10 ] Checking #def cylinder-homotopy-coherence
-[ 10 out of 10 ] Checking #def rev-cylinder-homotopy-coherence
-Checking module from /Users/nikolaikudasov/git/emilyriehl/yoneda/hott/4-equivalences.rzk
-[ 1 out of 39 ] Checking #def hasSection
-[ 2 out of 39 ] Checking #def hasRetraction
-[ 3 out of 39 ] Checking #def isEquiv
-[ 4 out of 39 ] Checking #def isEquiv-section
-[ 5 out of 39 ] Checking #def isEquiv-retraction
-[ 6 out of 39 ] Checking #def isEquiv-htpic-inverses
-[ 7 out of 39 ] Checking #def hasInverse
-[ 8 out of 39 ] Checking #def hasInverse-inverse
-[ 9 out of 39 ] Checking #def hasInverse-isEquiv
-[ 10 out of 39 ] Checking #def isEquiv-hasInverse
-[ 11 out of 39 ] Checking #def hasInverse-retraction-composite
-[ 12 out of 39 ] Checking #def hasInverse-section-composite
-[ 13 out of 39 ] Checking #def hasInverse-triple-composite
-[ 14 out of 39 ] Checking #def hasInverse-quintuple-composite
-[ 15 out of 39 ] Checking #def isHalfAdjointEquiv
-[ 16 out of 39 ] Checking #def ALTisHalfAdjointEquiv
-[ 17 out of 39 ] Checking #def hasInverse-kept-htpy
-[ 18 out of 39 ] Checking #def hasInverse-discarded-htpy
-[ 19 out of 39 ] Checking #def hasInverse-discarded-naturality-square
-[ 20 out of 39 ] Checking #def hasInverse-rev-cylinder-homotopy-coherence
-[ 21 out of 39 ] Checking #def hasInverse-ap-rev-cylinder-homotopy-coherence
-[ 22 out of 39 ] Checking #def hasInverse-cylinder-coherence
-[ 23 out of 39 ] Checking #def hasInverse-replaced-naturality-square
-[ 24 out of 39 ] Checking #def hasInverse-corrected-htpy
-[ 25 out of 39 ] Checking #def hasInverse-coherence
-[ 26 out of 39 ] Checking #def hasInverse-correctedhasInverse
-[ 27 out of 39 ] Checking #def hasInverse-isHalfAdjointEquiv
-[ 28 out of 39 ] Checking #def isEquiv-isHalfAdjointEquiv
-[ 29 out of 39 ] Checking #def iff
-[ 30 out of 39 ] Checking #def Eq
-[ 31 out of 39 ] Checking #def sym_Eq
-[ 32 out of 39 ] Checking #def compose_Eq
-[ 33 out of 39 ] Checking #def compose_isEquiv
-[ 34 out of 39 ] Checking #def triple_compose_Eq
-[ 35 out of 39 ] Checking #def triple_compose_isEquiv
-[ 36 out of 39 ] Checking #def FunExt
-[ 37 out of 39 ] Checking #def funext_test
-[ 38 out of 39 ] Checking #def fibered-equiv-function-iff
-[ 39 out of 39 ] Checking #def fibered-equiv-function-equiv
-Checking module from /Users/nikolaikudasov/git/emilyriehl/yoneda/hott/5-total-space.rzk
-[ 1 out of 25 ] Checking #def total-space-projection
-[ 2 out of 25 ] Checking #def contractible-fibers
-[ 3 out of 25 ] Checking #def contractible-fibers-section
-[ 4 out of 25 ] Checking #def contractible-fibers-actual-section
-[ 5 out of 25 ] Checking #def contractible-fibers-section-htpy
-[ 6 out of 25 ] Checking #def contractible-fibers-section-is-section
-[ 7 out of 25 ] Checking #def check
-[ 8 out of 25 ] Checking #def fibered-path-to-sigma-path
-[ 9 out of 25 ] Checking #def contractible-fibers-retraction-htpy
-[ 10 out of 25 ] Checking #def contractible-fibers-retraction
-[ 11 out of 25 ] Checking #def contractible-fibers-projection-equiv
-[ 12 out of 25 ] Checking #def total-path-to-base-path
-[ 13 out of 25 ] Checking #def total-path-to-fibered-path
-[ 14 out of 25 ] Checking #def projection-equiv-implies-inhabited-fibers
-[ 15 out of 25 ] Checking #def projection-coherent-equiv-inverse
-[ 16 out of 25 ] Checking #def projection-coherent-equiv-base-htpy
-[ 17 out of 25 ] Checking #def projection-coherent-equiv-section
-[ 18 out of 25 ] Checking #def projection-coherent-equiv-total-htpy
-[ 19 out of 25 ] Checking #def projection-coherent-equiv-fibered-htpy
-[ 20 out of 25 ] Checking #def projection-coherent-equiv-base-coherence
-[ 21 out of 25 ] Checking #def projection-coherent-equiv-transport-coherence
-[ 22 out of 25 ] Checking #def projection-coherent-equiv-fibered-contracting-htpy
-[ 23 out of 25 ] Checking #def projection-coherent-equiv-contractible-fibers
-[ 24 out of 25 ] Checking #def projection-equiv-contractible-fibers
-[ 25 out of 25 ] Checking #def projection-theorem
-Checking module from /Users/nikolaikudasov/git/emilyriehl/yoneda/3-simplicial-type-theory.md
-[ 1 out of 11 ] Checking #def Δ¹
-[ 2 out of 11 ] Checking #def Δ²
-[ 3 out of 11 ] Checking #def Δ³
-[ 4 out of 11 ] Checking #def ∂Δ¹
-[ 5 out of 11 ] Checking #def ∂Δ¹-in-Δ¹
-[ 6 out of 11 ] Checking #def ∂Δ²
-[ 7 out of 11 ] Checking #def Λ
-[ 8 out of 11 ] Checking #def shapeProd
-[ 9 out of 11 ] Checking #def Δ¹×Δ¹
-[ 10 out of 11 ] Checking #def ∂Δ¹×Δ¹
-[ 11 out of 11 ] Checking #def Δ²×Δ¹
-Checking module from /Users/nikolaikudasov/git/emilyriehl/yoneda/4-extension-types.md
-[ 1 out of 11 ] Checking #def extension-projection
-[ 2 out of 11 ] Checking #def flip-ext-fun
-[ 3 out of 11 ] Checking #def flip-ext-fun-inv
-[ 4 out of 11 ] Checking #def curry-uncurry
-[ 5 out of 11 ] Checking #def uncurry-opcurry
-[ 6 out of 11 ] Checking #def fubini
-[ 7 out of 11 ] Checking #def axiom-choice
-[ 8 out of 11 ] Checking #def cofibration_composition'
-[ 9 out of 11 ] Checking #def cofibration_union
-[ 10 out of 11 ] Checking #def ExtExt
-[ 11 out of 11 ] Checking #def fibered-equiv-extension-equiv
-Checking module from /Users/nikolaikudasov/git/emilyriehl/yoneda/5-segal-types.md
-[ 1 out of 61 ] Checking #def hom
-[ 2 out of 61 ] Checking #def hom2
-[ 3 out of 61 ] Checking #def hom2-triangle
-[ 4 out of 61 ] Checking #def isSegal
-[ 5 out of 61 ] Checking #def Segal-comp
-[ 6 out of 61 ] Checking #def Segal-comp-witness
-[ 7 out of 61 ] Checking #def Segal-comp-uniqueness
-[ 8 out of 61 ] Checking #def horn-restriction
-[ 9 out of 61 ] Checking #def identity-identity-composition
-[ 10 out of 61 ] Checking #def horn
-[ 11 out of 61 ] Checking #def compositions-are-horn-fillings
-[ 12 out of 61 ] Checking #def restriction-equiv
-[ 13 out of 61 ] Checking #def Segal-restriction-equiv
-[ 14 out of 61 ] Checking #def Segal-restriction-equiv-test
-[ 15 out of 61 ] Checking #def isSegal'
-[ 16 out of 61 ] Checking #def isSegal-isSegal'
-[ 17 out of 61 ] Checking #def isSegal'-isSegal
-[ 18 out of 61 ] Checking #def isSegal-iff-isSegal'
-[ 19 out of 61 ] Checking #def Segal-function-types-function
-[ 20 out of 61 ] Checking #def Segal-function-types-function'
-[ 21 out of 61 ] Checking #def Segal-function-types-function-pointwise-check
-[ 22 out of 61 ] Checking #def Segal-function-types-function-check
-[ 23 out of 61 ] Checking #def Segal-function-types
-[ 24 out of 61 ] Checking #def Segal-extension-types-function
-[ 25 out of 61 ] Checking #def Segal-extension-types-function'
-[ 26 out of 61 ] Checking #def Segal-extension-types-function-pointwise-check
-[ 27 out of 61 ] Checking #def Segal-extension-types-function-check
-[ 28 out of 61 ] Checking #def Segal-extension-types-start
-[ 29 out of 61 ] Checking #def Segal-extension-types-middle
-[ 30 out of 61 ] Checking #def Segal-extension-types-last
-[ 31 out of 61 ] Checking #def Segal-extension-types
-[ 32 out of 61 ] Checking #def arr
-[ 33 out of 61 ] Checking #def Segal'-arrow-types
-[ 34 out of 61 ] Checking #def Segal-arrow-types
-[ 35 out of 61 ] Checking #def id-arr
-[ 36 out of 61 ] Checking #def Segal-comp-id
-[ 37 out of 61 ] Checking #def Segal-id-comp
-[ 38 out of 61 ] Checking #def unbounded-arrow
-[ 39 out of 61 ] Checking #def unfolding-square
-[ 40 out of 61 ] Checking #def unfolding-square-test
-[ 41 out of 61 ] Checking #def unfolding-square-another-test
-[ 42 out of 61 ] Checking #def unfolding-square-yet-another-test
-[ 43 out of 61 ] Checking #def unfolding-square-horn-left-test
-[ 44 out of 61 ] Checking #def unfolding-square-horn-right-test
-[ 45 out of 61 ] Checking #def unfolding-square-horn-combined-test
-[ 46 out of 61 ] Checking #def square-to-arr-in-arr
-[ 47 out of 61 ] Checking #def Segal-comp-witness-triangle
-[ 48 out of 61 ] Checking #def Segal-comp-witness-square
-[ 49 out of 61 ] Checking #def Segal-arr-in-arr
-[ 50 out of 61 ] Checking #def Segal-horn-in-arrow
-[ 51 out of 61 ] Checking #def Segal-associativity-witness
-[ 52 out of 61 ] Checking #def Segal-associativity-prism
-[ 53 out of 61 ] Checking #def Segal-associativity-tetrahedron
-[ 54 out of 61 ] Checking #def Segal-triple-composite-also-fails
-[ 55 out of 61 ] Checking #def Segal-triple-composite-fails
-[ 56 out of 61 ] Checking #def Segal-triple-composite
-[ 57 out of 61 ] Checking #def Segal-left-associativity-witness
-[ 58 out of 61 ] Checking #def Segal-right-associativity-witness
-[ 59 out of 61 ] Checking #def Segal-left-associativity
-[ 60 out of 61 ] Checking #def Segal-right-associativity
-[ 61 out of 61 ] Checking #def Segal-associativity
-Checking module from /Users/nikolaikudasov/git/emilyriehl/yoneda/6-2cat-of-segal-types.md
-[ 1 out of 2 ] Checking #def ap
-[ 2 out of 2 ] Checking #def functors-pres-id
diff --git a/rzk/package.yaml b/rzk/package.yaml
index a60851c13..8ff8fef17 100644
--- a/rzk/package.yaml
+++ b/rzk/package.yaml
@@ -1,5 +1,5 @@
name: rzk
-version: 0.2.0
+version: 0.3.0
github: "fizruk/rzk"
license: BSD3
author: "Nikolai Kudasov"
diff --git a/rzk/rzk.cabal b/rzk/rzk.cabal
index d1f374483..1f2905484 100644
--- a/rzk/rzk.cabal
+++ b/rzk/rzk.cabal
@@ -4,10 +4,10 @@ cabal-version: 1.12
--
-- see: https://github.com/sol/hpack
--
--- hash: e731bc697ba22a070995646c30c641e0805466b3cabb2fdf377ce74e07985a32
+-- hash: 7855530fcdfd2a28c4ea3654677ed2d18f83d419f5d1c173f4bb44a915464c06
name: rzk
-version: 0.2.0
+version: 0.3.0
synopsis: An experimental proof assistant for synthetic ∞-categories
description: Please see the README on GitHub at
category: Dependent Types
diff --git a/rzk/src/Rzk/Main.hs b/rzk/src/Rzk/Main.hs
index a120f55a8..58ec566d5 100644
--- a/rzk/src/Rzk/Main.hs
+++ b/rzk/src/Rzk/Main.hs
@@ -1,5 +1,6 @@
module Rzk.Main where
+import System.Exit (exitFailure)
import System.Environment (getArgs)
import Control.Monad (forM)
@@ -22,11 +23,11 @@ main = do
case defaultTypeCheck (typecheckModulesWithLocation modules) of
Left err -> do
putStrLn "An error occurred when typechecking!"
- putStrLn "Rendering type error... (this may take a few seconds)"
putStrLn $ unlines
[ "Type Error:"
, ppTypeErrorInScopedContext' err
]
+ exitFailure
Right () -> putStrLn "Everything is ok!"
_ -> ppUsage
diff --git a/rzk/src/Rzk/TypeCheck.hs b/rzk/src/Rzk/TypeCheck.hs
index 76e7e49bf..485c45787 100644
--- a/rzk/src/Rzk/TypeCheck.hs
+++ b/rzk/src/Rzk/TypeCheck.hs
@@ -1,4 +1,7 @@
+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TupleSections #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE RecordWildCards #-}
@@ -84,8 +87,15 @@ typecheckModule (Rzk.Module _loc _lang commands) = go 1 commands
term' <- typecheck (toTerm' (addParams params term)) ty' >>= whnfT >>= pure . termIsWHNF
let decl = Decl name ty' (Just term')
fmap (decl :) $
- localDeclPrepared decl $
- go (i + 1) moreCommands
+ localDeclPrepared decl $ do
+ Context{..} <- ask
+ termSVG <-
+ case renderBackend of
+ Just RenderSVG -> renderTermSVG (Pure name)
+ Just RenderLaTeX -> issueTypeError $ TypeErrorOther "\"latex\" rendering is not yet supported"
+ Nothing -> pure Nothing
+ maybe id trace termSVG $ do
+ go (i + 1) moreCommands
go i (command@(Rzk.CommandPostulate _loc name params ty) : moreCommands) =
traceTypeCheck Normal ("[ " <> show i <> " out of " <> show totalCommands <> " ]"
@@ -132,6 +142,12 @@ setOption "verbosity" = \case
"silent" -> localVerbosity Silent
_ -> const $
issueTypeError $ TypeErrorOther "unknown verbosity level (use \"debug\", \"normal\", or \"silent\")"
+setOption "render" = \case
+ "svg" -> localRenderBackend (Just RenderSVG)
+ "latex" -> localRenderBackend (Just RenderLaTeX)
+ "none" -> localRenderBackend Nothing
+ _ -> const $
+ issueTypeError $ TypeErrorOther "unknown render backend (use \"svg\", \"latex\", or \"none\")"
setOption optionName = const $ const $
issueTypeError $ TypeErrorOther ("unknown option " <> show optionName)
@@ -328,9 +344,9 @@ data Action var
| ActionUnify (TermT var) (TermT var) (TermT var)
| ActionUnifyTerms (TermT var) (TermT var)
| ActionInfer (Term var)
- | ActionContextEntailedBy (TermT var)
- | ActionContextEntails (TermT var)
- | ActionContextEquiv [TermT var]
+ | ActionContextEntailedBy [TermT var] (TermT var)
+ | ActionContextEntails [TermT var] (TermT var)
+ | ActionContextEquiv [TermT var] [TermT var]
| ActionWHNF (TermT var)
| ActionNF (TermT var)
| ActionCheckCoherence (TermT var, TermT var) (TermT var, TermT var)
@@ -338,6 +354,16 @@ data Action var
type Action' = Action Rzk.VarIdent
+ppTermInContext :: Eq var => TermT var -> TypeCheck var String
+ppTermInContext term = do
+ Context{..} <- ask
+ return (show (untyped (toRzkVarIdent varOrigs <$> term)))
+ where
+ vars = nub (foldMap pure term)
+ mapping = zip vars defaultVarIdents
+ toRzkVarIdent origs var = fromMaybe (Rzk.VarIdent "_") $
+ join (lookup var origs) <|> lookup var mapping
+
ppSomeAction :: Eq var => [(var, Maybe Rzk.VarIdent)] -> Int -> Action var -> String
ppSomeAction origs n action = ppAction n (toRzkVarIdent <$> action)
where
@@ -372,16 +398,22 @@ ppAction n = unlines . map (replicate (2 * n) ' ' <>) . \case
[ "inferring type for term"
, " " <> show term ]
- ActionContextEntailedBy term ->
- [ "checking if local context includes (is entailed by) restriction tope"
+ ActionContextEntailedBy ctxTopes term ->
+ [ "checking if local context"
+ , intercalate "\n" (map ((" " <>) . show . untyped) ctxTopes)
+ , "includes (is entailed by) restriction tope"
, " " <> show (untyped term) ]
- ActionContextEntails term ->
- [ "checking if local context is included in (entails) the tope"
+ ActionContextEntails ctxTopes term ->
+ [ "checking if local context"
+ , intercalate "\n" (map ((" " <>) . show . untyped) ctxTopes)
+ , "is included in (entails) the tope"
, " " <> show (untyped term) ]
- ActionContextEquiv terms ->
- [ "checking if local context is equivalent to the union of the topes"
+ ActionContextEquiv ctxTopes terms ->
+ [ "checking if local context"
+ , intercalate "\n" (map ((" " <>) . show . untyped) ctxTopes)
+ , "is equivalent to the union of the topes"
, intercalate "\n" (map ((" " <>) . show . untyped) terms) ]
ActionWHNF term ->
@@ -431,10 +463,17 @@ traceTypeCheck msgLevel msg tc = do
localVerbosity :: Verbosity -> TypeCheck var a -> TypeCheck var a
localVerbosity v = local $ \Context{..} -> Context { verbosity = v, .. }
+localRenderBackend :: Maybe RenderBackend -> TypeCheck var a -> TypeCheck var a
+localRenderBackend v = local $ \Context{..} -> Context { renderBackend = v, .. }
+
data Covariance
= Covariant -- ^ Positive position.
| Contravariant -- ^ Negative position
+data RenderBackend
+ = RenderSVG
+ | RenderLaTeX
+
data Context var = Context
{ varTypes :: [(var, TermT var)]
, varValues :: [(var, Maybe (TermT var))]
@@ -448,6 +487,7 @@ data Context var = Context
, location :: Maybe LocationInfo
, verbosity :: Verbosity
, covariance :: Covariance
+ , renderBackend :: Maybe RenderBackend
} deriving (Functor, Foldable)
emptyContext :: Context var
@@ -455,15 +495,16 @@ emptyContext = Context
{ varTypes = []
, varValues = []
, varOrigs = []
- , localTopes = []
- , localTopesNF = []
- , localTopesNFUnion = [[]]
+ , localTopes = [topeTopT]
+ , localTopesNF = [topeTopT]
+ , localTopesNFUnion = [[topeTopT]]
, localTopesEntailBottom = False
, actionStack = []
, currentCommand = Nothing
, location = Nothing
, verbosity = Normal
, covariance = Covariant
+ , renderBackend = Nothing
}
ppContext' :: Context Rzk.VarIdent -> String
@@ -730,25 +771,46 @@ solveRHS topes tope =
_ -> tope `elem` topes
checkTope :: Eq var => TermT var -> TypeCheck var Bool
-checkTope tope = performing (ActionContextEntails tope) $ do
- topes' <- asks localTopesNF
- tope' <- nfTope tope
- return (topes' `entail` tope')
+checkTope tope = do
+ ctxTopes <- asks localTopes
+ performing (ActionContextEntails ctxTopes tope) $ do
+ topes' <- asks localTopesNF
+ tope' <- nfTope tope
+ return (topes' `entail` tope')
+
+checkTopeEntails :: Eq var => TermT var -> TypeCheck var Bool
+checkTopeEntails tope = do
+ ctxTopes <- asks localTopes
+ performing (ActionContextEntailedBy ctxTopes tope) $ do
+ contextTopes <- asks localTopesNF
+ restrictionTope <- nfTope tope
+ let contextTopesRHS = foldr topeAndT topeTopT contextTopes
+ return ([restrictionTope] `entail` contextTopesRHS)
+
+checkEntails :: Eq var => TermT var -> TermT var -> TypeCheck var Bool
+checkEntails l r = do -- FIXME: add action
+ l' <- nfTope l
+ r' <- nfTope r
+ return ([l'] `entail` r')
contextEntailedBy :: Eq var => TermT var -> TypeCheck var ()
-contextEntailedBy tope = performing (ActionContextEntailedBy tope) $ do
- contextTopes <- asks localTopesNF
- restrictionTope <- nfTope tope
- let contextTopesRHS = foldr topeOrT topeBottomT contextTopes
- unless ([restrictionTope] `entail` contextTopesRHS) $
- issueTypeError $ TypeErrorTopeNotSatisfied [restrictionTope] contextTopesRHS
+contextEntailedBy tope = do
+ ctxTopes <- asks localTopes
+ performing (ActionContextEntailedBy ctxTopes tope) $ do
+ contextTopes <- asks localTopesNF
+ restrictionTope <- nfTope tope
+ let contextTopesRHS = foldr topeOrT topeBottomT contextTopes
+ unless ([restrictionTope] `entail` contextTopesRHS) $
+ issueTypeError $ TypeErrorTopeNotSatisfied [restrictionTope] contextTopesRHS
contextEntails :: Eq var => TermT var -> TypeCheck var ()
-contextEntails tope = performing (ActionContextEntails tope) $ do
- topeIsEntailed <- checkTope tope
- topes' <- asks localTopesNF
- unless topeIsEntailed $
- issueTypeError $ TypeErrorTopeNotSatisfied topes' tope
+contextEntails tope = do
+ ctxTopes <- asks localTopes
+ performing (ActionContextEntails ctxTopes tope) $ do
+ topeIsEntailed <- checkTope tope
+ topes' <- asks localTopesNF
+ unless topeIsEntailed $
+ issueTypeError $ TypeErrorTopeNotSatisfied topes' tope
topesEquiv :: Eq var => TermT var -> TermT var -> TypeCheck var Bool
topesEquiv expected actual = performing (ActionUnifyTerms expected actual) $ do
@@ -757,15 +819,17 @@ topesEquiv expected actual = performing (ActionUnifyTerms expected actual) $ do
return ([expected'] `entail` actual' && [actual'] `entail` expected')
contextEquiv :: Eq var => [TermT var] -> TypeCheck var ()
-contextEquiv topes = performing (ActionContextEquiv topes) $ do
- contextTopes <- asks localTopesNF
- recTopes <- mapM nfTope topes
- let contextTopesRHS = foldr topeOrT topeBottomT contextTopes
- recTopesRHS = foldr topeOrT topeBottomT recTopes
- unless (contextTopes `entail` recTopesRHS) $
- issueTypeError $ TypeErrorTopeNotSatisfied contextTopes recTopesRHS
- unless (recTopes `entail` contextTopesRHS) $
- issueTypeError $ TypeErrorTopeNotSatisfied recTopes contextTopesRHS
+contextEquiv topes = do
+ ctxTopes <- asks localTopes
+ performing (ActionContextEquiv ctxTopes topes) $ do
+ contextTopes <- asks localTopesNF
+ recTopes <- mapM nfTope topes
+ let contextTopesRHS = foldr topeOrT topeBottomT contextTopes
+ recTopesRHS = foldr topeOrT topeBottomT recTopes
+ unless (contextTopes `entail` recTopesRHS) $
+ issueTypeError $ TypeErrorTopeNotSatisfied contextTopes recTopesRHS
+ unless (recTopes `entail` contextTopesRHS) $
+ issueTypeError $ TypeErrorTopeNotSatisfied recTopes contextTopesRHS
switchVariance :: TypeCheck var a -> TypeCheck var a
switchVariance = local $ \Context{..} -> Context
@@ -1492,7 +1556,7 @@ localTope tope tc = do
-- A small optimisation to help unify terms faster
let refine = case tope' of
TopeEQT _ x y | x == y -> const tc -- no new information added!
- _ | tope' `elem` localTopes -> const tc
+ _ | tope' `elem` localTopes -> const tc -- no new information added!
| otherwise -> id
refine $ do
local (f tope' localTopesNF) tc
@@ -2074,7 +2138,7 @@ infer tt = performing (ActionInfer tt) $ case tt of
ret <- typeOf body'
return (lambdaT (typeFunT orig ty' mtope ret) orig (Just (ty', mtope)) body')
Lambda orig (Just (cube, Just tope)) body -> do
- cube' <- typecheck cube universeT
+ cube' <- typecheck cube cubeT
mapM_ checkNameShadowing orig
enterScope orig cube' $ do
tope' <- infer tope
@@ -2126,6 +2190,7 @@ infer tt = performing (ActionInfer tt) $ case tt of
tope' <- typecheck tope topeT
term' <- localTope tope' $ typecheck term ty'
return (tope', term')
+ sequence_ [ checkCoherence l r | l:rs'' <- tails rs', r <- rs'' ]
return (typeRestrictedT ty' rs')
checkCoherence
@@ -2153,3 +2218,576 @@ unsafeInferStandalone' t =
, ppTypeErrorInScopedContext' err
]
Right tt -> tt
+
+type PointId = String
+type ShapeId = [PointId]
+
+cube2powerT :: Int -> TermT var
+cube2powerT 1 = cube2T
+cube2powerT dim = cubeProductT (cube2powerT (dim - 1)) cube2T
+
+splits :: [a] -> [([a], [a])]
+splits [] = [([], [])]
+splits (x:xs) = ([], x:xs) : [ (x : before, after) | (before, after) <- splits xs ]
+
+verticesFrom :: [TermT var] -> [(ShapeId, TermT var)]
+verticesFrom ts = combine <$> mapM mk ts
+ where
+ mk t = [("0", topeEQT t cube2_0T), ("1", topeEQT t cube2_1T)]
+ combine xs = ([concat (map fst xs)], foldr1 topeAndT (map snd xs))
+
+subTopes2 :: Int -> TermT var -> [(ShapeId, TermT var)]
+-- 1-dim
+subTopes2 1 t =
+ [ (words "0", topeEQT t cube2_0T)
+ , (words "1", topeEQT t cube2_1T)
+ , (words "0 1", topeTopT) ]
+-- 2-dim
+subTopes2 2 ts =
+ -- vertices
+ [ (words "00", topeEQT t cube2_0T `topeAndT` topeEQT s cube2_0T)
+ , (words "01", topeEQT t cube2_0T `topeAndT` topeEQT s cube2_1T)
+ , (words "10", topeEQT t cube2_1T `topeAndT` topeEQT s cube2_0T)
+ , (words "11", topeEQT t cube2_1T `topeAndT` topeEQT s cube2_1T)
+ -- edges and the diagonal
+ , (words "00 01", topeEQT t cube2_0T)
+ , (words "10 11", topeEQT t cube2_1T)
+ , (words "00 10", topeEQT s cube2_0T)
+ , (words "01 11", topeEQT s cube2_1T)
+ , (words "00 11", topeEQT s t)
+ -- triangles
+ , (words "00 01 11", topeLEQT t s)
+ , (words "00 10 11", topeLEQT s t)
+ ]
+ where
+ t = firstT cube2T ts
+ s = secondT cube2T ts
+-- 3-dim
+subTopes2 3 t =
+ -- vertices
+ [ (words "000", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_0T)
+ , (words "001", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_1T)
+ , (words "010", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_0T)
+ , (words "011", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_1T)
+ , (words "100", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_0T)
+ , (words "101", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_1T)
+ , (words "110", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_0T)
+ , (words "111", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_1T)
+ -- edges
+ , (words "000 001", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_0T)
+ , (words "010 011", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_1T)
+ , (words "000 010", topeEQT t1 cube2_0T `topeAndT` topeEQT t3 cube2_0T)
+ , (words "001 011", topeEQT t1 cube2_0T `topeAndT` topeEQT t3 cube2_1T)
+ , (words "100 101", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_0T)
+ , (words "110 111", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_1T)
+ , (words "100 110", topeEQT t1 cube2_1T `topeAndT` topeEQT t3 cube2_0T)
+ , (words "101 111", topeEQT t1 cube2_1T `topeAndT` topeEQT t3 cube2_1T)
+ , (words "000 100", topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_0T)
+ , (words "001 101", topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_1T)
+ , (words "010 110", topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_0T)
+ , (words "011 111", topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_1T)
+ -- face diagonals
+ , (words "000 011", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 t3)
+ , (words "100 111", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 t3)
+ , (words "000 101", topeEQT t2 cube2_0T `topeAndT` topeEQT t1 t3)
+ , (words "010 111", topeEQT t2 cube2_1T `topeAndT` topeEQT t1 t3)
+ , (words "000 110", topeEQT t3 cube2_0T `topeAndT` topeEQT t1 t2)
+ , (words "001 111", topeEQT t3 cube2_1T `topeAndT` topeEQT t1 t2)
+ -- the long diagonal
+ , (words "000 111", topeEQT t3 t2 `topeAndT` topeEQT t2 t1)
+ -- face triangles
+ , (words "000 001 011", topeEQT t1 cube2_0T `topeAndT` topeLEQT t2 t3)
+ , (words "000 010 011", topeEQT t1 cube2_0T `topeAndT` topeLEQT t3 t2)
+ , (words "100 101 111", topeEQT t1 cube2_1T `topeAndT` topeLEQT t2 t3)
+ , (words "100 110 111", topeEQT t1 cube2_1T `topeAndT` topeLEQT t3 t2)
+ , (words "000 001 101", topeEQT t2 cube2_0T `topeAndT` topeLEQT t1 t3)
+ , (words "000 100 101", topeEQT t2 cube2_0T `topeAndT` topeLEQT t3 t1)
+ , (words "010 011 111", topeEQT t2 cube2_1T `topeAndT` topeLEQT t1 t3)
+ , (words "010 110 111", topeEQT t2 cube2_1T `topeAndT` topeLEQT t3 t1)
+ , (words "000 010 110", topeEQT t3 cube2_0T `topeAndT` topeLEQT t1 t2)
+ , (words "000 100 110", topeEQT t3 cube2_0T `topeAndT` topeLEQT t2 t1)
+ , (words "001 011 111", topeEQT t3 cube2_1T `topeAndT` topeLEQT t1 t2)
+ , (words "001 101 111", topeEQT t3 cube2_1T `topeAndT` topeLEQT t2 t1)
+ -- diagonal triangles
+ , (words "000 001 111", topeEQT t1 t2 `topeAndT` topeLEQT t2 t3)
+ , (words "000 010 111", topeEQT t1 t3 `topeAndT` topeLEQT t1 t2)
+ , (words "000 100 111", topeEQT t2 t3 `topeAndT` topeLEQT t2 t1)
+ , (words "000 011 111", topeLEQT t1 t2 `topeAndT` topeEQT t2 t3)
+ , (words "000 101 111", topeLEQT t2 t1 `topeAndT` topeEQT t1 t3)
+ , (words "000 110 111", topeLEQT t3 t1 `topeAndT` topeEQT t1 t2)
+ -- tetrahedra
+ , (words "000 001 011 111", topeLEQT t1 t2 `topeAndT` topeLEQT t2 t3)
+ , (words "000 010 011 111", topeLEQT t1 t3 `topeAndT` topeLEQT t3 t2)
+ , (words "000 001 101 111", topeLEQT t2 t1 `topeAndT` topeLEQT t1 t3)
+ , (words "000 100 101 111", topeLEQT t2 t3 `topeAndT` topeLEQT t3 t1)
+ , (words "000 010 110 111", topeLEQT t3 t1 `topeAndT` topeLEQT t1 t2)
+ , (words "000 100 110 111", topeLEQT t3 t2 `topeAndT` topeLEQT t2 t1)
+ ]
+ where
+ t1 = firstT cube2T (firstT (cube2powerT 2) t)
+ t2 = secondT cube2T (firstT (cube2powerT 2) t)
+ t3 = secondT cube2T t
+subTopes2 dim _ = error (show dim <> " dimensions are not supported")
+
+cubeSubTopes :: [(ShapeId, TermT (Inc var))]
+cubeSubTopes = subTopes2 3 (Pure Z)
+
+limitLength :: Int -> String -> String
+limitLength n s
+ | length s > n = take (n - 1) s <> "…"
+ | otherwise = s
+
+renderObjectsFor
+ :: Eq var
+ => String
+ -> Int
+ -> TermT var
+ -> TermT var
+ -> TypeCheck var [(ShapeId, RenderObjectData)]
+renderObjectsFor mainColor dim t term = fmap catMaybes $ do
+ forM (subTopes2 dim t) $ \(shapeId, tope) -> do
+ checkTopeEntails tope >>= \case
+ False -> return Nothing
+ True -> typeOf term >>= \case
+ UniverseTopeT{} -> localTope term $ checkTopeEntails tope >>= \case
+ False -> return Nothing
+ True -> return $ Just (shapeId, RenderObjectData
+ { renderObjectDataLabel = ""
+ , renderObjectDataFullLabel = ""
+ , renderObjectDataColor = "orange" -- FIXME: orange for topes?
+ })
+ _ -> do
+ Context{..} <- ask
+ term' <- localTope tope $ whnfT term
+ label <-
+ case term' of
+ AppT _ (Pure z) arg
+ | Just (Just "_") <- lookup z varOrigs -> return ""
+ | null (nub (foldMap pure arg) \\ nub (foldMap pure t)) -> ppTermInContext (Pure z)
+ _ -> ppTermInContext term'
+ return $ Just (shapeId, RenderObjectData
+ { renderObjectDataLabel = label
+ , renderObjectDataFullLabel = label
+ , renderObjectDataColor =
+ case term' of
+ Pure{} -> "purple"
+ AppT _ (Pure x) arg
+ | Just (Just "_") <- lookup x varOrigs -> mainColor
+ | null (nub (foldMap pure arg) \\ nub (foldMap pure t)) -> "purple"
+ _ -> mainColor
+ })
+
+componentWiseEQT :: Int -> TermT var -> TermT var -> TermT var
+componentWiseEQT 1 t s = topeEQT t s
+componentWiseEQT 2 t s = topeAndT
+ (componentWiseEQT 1 (firstT cube2T t) (firstT cube2T s))
+ (componentWiseEQT 1 (secondT cube2T t) (secondT cube2T s))
+componentWiseEQT 3 t s = topeAndT
+ (componentWiseEQT 2 (firstT (cube2powerT 2) t) (firstT (cube2powerT 2) s))
+ (componentWiseEQT 1 (secondT cube2T t) (secondT cube2T s))
+componentWiseEQT dim _ _ = error ("cannot work with " <> show dim <> " dimensions")
+
+renderObjectsInSubShapeFor
+ :: Eq var
+ => String
+ -> Int
+ -> [var]
+ -> var
+ -> TermT var
+ -> TermT var
+ -> TermT var
+ -> TypeCheck var [(ShapeId, RenderObjectData)]
+renderObjectsInSubShapeFor mainColor dim sub super retType f x = fmap catMaybes $ do
+ let reduceContext
+ = foldr topeOrT topeBottomT
+ . map (foldr topeAndT topeTopT)
+ . map (filter (\tope -> all (`notElem` tope) sub))
+ . map (saturateTopes [])
+ . simplifyLHS
+ contextTopes <- asks (reduceContext . localTopesNF)
+ contextTopes' <- localTope (componentWiseEQT dim (Pure super) x) $ asks (reduceContext . localTopesNF)
+ forM (subTopes2 dim (Pure super)) $ \(shapeId, tope) -> do
+ checkEntails tope contextTopes >>= \case
+ False -> return Nothing
+ True -> do
+ Context{..} <- ask
+ term <- localTope tope (whnfT (appT retType f (Pure super)))
+ label <- typeOf term >>= \case
+ UniverseTopeT{} -> return ""
+ _ -> do
+ case term of
+ AppT _ (Pure z) arg
+ | Just (Just "_") <- lookup z varOrigs -> return ""
+ | null (nub (foldMap pure arg) \\ [super]) -> ppTermInContext (Pure z)
+ _ -> ppTermInContext term
+ color <- checkEntails tope contextTopes' >>= \case
+ True -> do
+ case term of
+ Pure{} -> return "purple"
+ AppT _ (Pure z) arg
+ | Just (Just "_") <- lookup z varOrigs -> return mainColor
+ | null (nub (foldMap pure arg) \\ [super]) -> return "purple"
+ _ -> return mainColor
+ False -> return "gray"
+ return $ Just (shapeId, RenderObjectData
+ { renderObjectDataLabel = label
+ , renderObjectDataFullLabel = label
+ , renderObjectDataColor = color
+ })
+
+renderForSubShapeSVG
+ :: Eq var
+ => String
+ -> Int
+ -> [var]
+ -> var
+ -> TermT var
+ -> TermT var
+ -> TermT var
+ -> TypeCheck var String
+renderForSubShapeSVG mainColor dim sub super retType f x = do
+ objects <- renderObjectsInSubShapeFor mainColor dim sub super retType f x
+ let objects' = map mk objects
+ return $ renderCube defaultCamera (if dim > 2 then (pi/7) else 0) $ \obj ->
+ lookup obj objects'
+ where
+ mk (shapeId, renderData) = (intercalate "-" (map fill shapeId), renderData)
+ fill xs = xs <> replicate (3 - length xs) '1'
+
+renderForSVG :: Eq var => String -> Int -> TermT var -> TermT var -> TypeCheck var String
+renderForSVG mainColor dim t term = do
+ objects <- renderObjectsFor mainColor dim t term
+ let objects' = map mk objects
+ return $ renderCube defaultCamera (if dim > 2 then (pi/7) else 0) $ \obj ->
+ lookup obj objects'
+ where
+ mk (shapeId, renderData) = (intercalate "-" (map fill shapeId), renderData)
+ fill xs = xs <> replicate (3 - length xs) '1'
+
+renderTermSVGFor
+ :: Eq var
+ => String -- ^ Main color.
+ -> Int -- ^ Accumulated dimensions so far (from 0 to 3).
+ -> (Maybe (TermT var, TermT var), [var]) -- ^ Accumulated point term (and its time).
+ -> TermT var -- ^ Term to render.
+ -> TypeCheck var (Maybe String)
+renderTermSVGFor mainColor accDim (mp, xs) t = do
+ t' <- whnfT t
+ ty <- typeOf t'
+ case t of -- check unevaluated term
+ AppT _info f x -> typeOf f >>= \case
+ TypeFunT _ fOrig fArg mtopeArg ret | Just dim <- dimOf fArg, dim <= maxDim -> do
+ enterScope fOrig fArg $ do
+ maybe id localTope mtopeArg $ do
+ Just <$> renderForSubShapeSVG mainColor dim (map S xs) Z ret (S <$> f) (S <$> x) -- FIXME: breaks for 2 * (2 * 2), but works for 2 * 2 * 2 = (2 * 2) * 2
+ _ -> traverse (\(p', _) -> renderForSVG mainColor accDim p' t') mp
+ TypeFunT{} | null xs -> enterScope (Just "_") t' $ do
+ renderTermSVGFor "blue" 0 (Nothing, []) (Pure Z) -- use blue for types
+
+ _ -> case t' of -- check evaluated term
+ AppT _info f x -> typeOf f >>= \case
+ TypeFunT _ fOrig fArg mtopeArg ret | Just dim <- dimOf fArg, dim <= maxDim -> do
+ enterScope fOrig fArg $ do
+ maybe id localTope mtopeArg $ do
+ Just <$> renderForSubShapeSVG mainColor dim (map S xs) Z ret (S <$> f) (S <$> x) -- FIXME: breaks for 2 * (2 * 2), but works for 2 * 2 * 2 = (2 * 2) * 2
+ _ -> traverse (\(p', _) -> renderForSVG mainColor accDim p' t') mp
+ TypeFunT{} | null xs -> enterScope (Just "_") t' $ do
+ renderTermSVGFor "blue" 0 (Nothing, []) (Pure Z) -- use blue for types
+
+ _ -> case ty of -- check type of the term
+ TypeFunT _ orig arg mtope ret
+ | Just dim <- dimOf arg, accDim + dim <= maxDim -> enterScope orig arg $ do
+ maybe id localTope mtope $
+ renderTermSVGFor mainColor (accDim + dim)
+ (join' (both (fmap S) <$> mp) (S <$> arg) (Pure Z), Z : map S xs) $
+ case t' of
+ LambdaT _ _orig _marg body -> body
+ _ -> appT ret (S <$> t') (Pure Z)
+ | null xs -> enterScope orig arg $ do
+ maybe id localTope mtope $
+ renderTermSVGFor mainColor accDim
+ (both (fmap S) <$> mp, map S xs) $
+ case t' of
+ LambdaT _ _orig _marg body -> body
+ _ -> appT ret (S <$> t') (Pure Z)
+ _ -> traverse (\(p', _) -> renderForSVG mainColor accDim p' t') mp
+ where
+ maxDim = 3
+
+ both f (x, y) = (f x, f y)
+
+ join' Nothing Cube2T{} x = Just (x, cube2T)
+ join' (Just (p, pt)) Cube2T{} x = Just (p', pt')
+ where
+ pt' = cubeProductT pt cube2T
+ p' = pairT pt' p x
+ join' p (CubeProductT _ l r) x =
+ join' (join' p l (firstT l x)) r (secondT r x)
+ join' _ _ _ = Nothing -- FIXME: error?
+
+ dimOf = \case
+ Cube2T{} -> Just 1
+ CubeProductT _ l r -> (+) <$> dimOf l <*> dimOf r
+ _ -> Nothing
+
+renderTermSVG :: Eq var => TermT var -> TypeCheck var (Maybe String)
+renderTermSVG = renderTermSVGFor "red" 0 (Nothing, []) -- use red for terms by default
+
+renderTermSVG' :: Eq var => TermT var -> TypeCheck var (Maybe String)
+renderTermSVG' t = whnfT t >>= \t' -> typeOf t >>= \case
+ TypeFunT _ orig arg mtope ret -> enterScope orig arg $ do
+ maybe id localTope mtope $ case t' of
+ LambdaT _ _orig _marg (AppT _info f x) ->
+ typeOf f >>= \case
+ TypeFunT _ fOrig fArg mtope2 _ret | Just dim <- dimOf fArg -> do
+ enterScope fOrig fArg $ do
+ maybe id localTope mtope2 $ do
+ Just <$> renderForSubShapeSVG "red" dim [S Z] Z (S <$> ret) (S <$> f) (S <$> x)
+ _ -> defaultRenderTermSVG t' arg ret
+ _ -> defaultRenderTermSVG t' arg ret
+ _t' -> return Nothing
+ where
+ dimOf = \case
+ Cube2T{} -> Just 1
+ CubeProductT _ l r -> (+) <$> dimOf l <*> dimOf r -- WARNING: breaks for 2 * (2 * 2)
+ _ -> Nothing
+
+ defaultRenderTermSVG t' arg ret =
+ case dimOf arg of
+ Just dim | dim <= 3 ->
+ Just <$> renderForSVG "red" dim (Pure Z) (appT ret (S <$> t') (Pure Z))
+ _ -> renderTermSVG' (appT ret (S <$> t') (Pure Z))
+
+
+type Point2D a = (a, a)
+type Point3D a = (a, a, a)
+type Edge3D a = (Point3D a, Point3D a)
+type Face3D a = (Point3D a, Point3D a, Point3D a)
+type Volume3D a = (Point3D a, Point3D a, Point3D a, Point3D a)
+
+data CubeCoords2D a b = CubeCoords2D
+ { vertices :: [(Point3D a, Point2D b)]
+ , edges :: [(Edge3D a, (Point2D b, Point2D b))]
+ , faces :: [(Face3D a, (Point2D b, Point2D b, Point2D b))]
+ , volumes :: [(Volume3D a, (Point2D b, Point2D b, Point2D b, Point2D b))]
+ }
+
+data Matrix3D a = Matrix3D
+ a a a
+ a a a
+ a a a
+
+data Matrix4D a = Matrix4D
+ a a a a
+ a a a a
+ a a a a
+ a a a a
+
+data Vector3D a = Vector3D a a a
+
+data Vector4D a = Vector4D a a a a
+
+rotateX :: Floating a => a -> Matrix3D a
+rotateX theta = Matrix3D
+ 1 0 0
+ 0 (cos theta) (- sin theta)
+ 0 (sin theta) (cos theta)
+
+rotateY :: Floating a => a -> Matrix3D a
+rotateY theta = Matrix3D
+ (cos theta) 0 (sin theta)
+ 0 1 0
+ (- sin theta) 0 (cos theta)
+
+rotateZ :: Floating a => a -> Matrix3D a
+rotateZ theta = Matrix3D
+ (cos theta) (- sin theta) 0
+ (sin theta) (cos theta) 0
+ 0 0 1
+
+data Camera a = Camera
+ { cameraPos :: Point3D a
+ , cameraFoV :: a
+ , cameraAspectRatio :: a
+ , cameraAngleY :: a
+ , cameraAngleX :: a
+ }
+
+viewRotateX :: Floating a => Camera a -> Matrix4D a
+viewRotateX Camera{..} = matrix3Dto4D (rotateX cameraAngleX)
+
+viewRotateY :: Floating a => Camera a -> Matrix4D a
+viewRotateY Camera{..} = matrix3Dto4D (rotateY cameraAngleY)
+
+viewTranslate :: Num a => Camera a -> Matrix4D a
+viewTranslate Camera{..} = Matrix4D
+ 1 0 0 0
+ 0 1 0 0
+ 0 0 1 0
+ (-x) (-y) (-z) 1
+ where
+ (x, y, z) = cameraPos
+
+project2D :: Floating a => Camera a -> Matrix4D a
+project2D Camera{..} = Matrix4D
+ (2 * n / (r - l)) 0 ((r + l) / (r - l)) 0
+ 0 (2 * n / (t - b)) ((t + b) / (t - b)) 0
+ 0 0 (- (f + n) / (f - n)) (- 2 * f * n / (f - n))
+ 0 0 (-1) 0
+ where
+ n = 1
+ f = 2
+ r = n * tan (cameraFoV / 2)
+ l = -r
+ t = r * cameraAspectRatio
+ b = -t
+
+
+matrixVectorMult4D :: Num a => Matrix4D a -> Vector4D a -> Vector4D a
+matrixVectorMult4D
+ (Matrix4D
+ a1 a2 a3 a4
+ b1 b2 b3 b4
+ c1 c2 c3 c4
+ d1 d2 d3 d4)
+ (Vector4D a b c d)
+ = Vector4D a' b' c' d'
+ where
+ a' = sum (zipWith (*) [a1, b1, c1, d1] [a, b, c, d])
+ b' = sum (zipWith (*) [a2, b2, c2, d2] [a, b, c, d])
+ c' = sum (zipWith (*) [a3, b3, c3, d3] [a, b, c, d])
+ d' = sum (zipWith (*) [a4, b4, c4, d4] [a, b, c, d])
+
+matrix3Dto4D :: Num a => Matrix3D a -> Matrix4D a
+matrix3Dto4D
+ (Matrix3D
+ a1 b1 c1
+ a2 b2 c2
+ a3 b3 c3) = Matrix4D
+ a1 b1 c1 0
+ a2 b2 c2 0
+ a3 b3 c3 0
+ 0 0 0 1
+
+fromAffine :: Fractional a => Vector4D a -> (Point2D a, a)
+fromAffine (Vector4D a b c d) = ((x, y), zIndex)
+ where
+ x = a / d
+ y = b / d
+ zIndex = c / d
+
+point3Dto2D :: Floating a => Camera a -> a -> Point3D a -> (Point2D a, a)
+point3Dto2D camera rotY (x, y, z) = fromAffine $
+ foldr matrixVectorMult4D (Vector4D x y z 1) $ reverse
+ [ matrix3Dto4D (rotateY rotY)
+ , viewTranslate camera
+ , viewRotateY camera
+ , viewRotateX camera
+ , project2D camera
+ ]
+
+data RenderObjectData = RenderObjectData
+ { renderObjectDataLabel :: String
+ , renderObjectDataFullLabel :: String
+ , renderObjectDataColor :: String
+ }
+
+renderCube
+ :: (Floating a, Show a)
+ => Camera a
+ -> a
+ -> (String -> Maybe RenderObjectData)
+ -> String
+renderCube camera rotY renderDataOf' = unlines $ filter (not . null)
+ [ ""
+ , intercalate "\n"
+ [ " show x1 <> " " <> show y1
+ <> " L " <> show x2 <> " " <> show y2
+ <> " L " <> show x3 <> " " <> show y3
+ <> " Z\" style=\"fill: " <> renderObjectDataColor <> "; opacity: 0.2\">" <> renderObjectDataFullLabel <> " " <> "\n" <>
+ " show x <> "\" y=\"" <> show y <> "\" fill=\"" <> renderObjectDataColor <> "\">" <> renderObjectDataLabel <> " "
+ | (faceId, (((x1, y1), (x2, y2), (x3, y3)), _)) <- faces
+ , Just RenderObjectData{..} <- [renderDataOf faceId]
+ , let x = (x1 + x2 + x3) / 3
+ , let y = (y1 + y2 + y3) / 3 ]
+ , intercalate "\n"
+ [ " show x1 <> "," <> show y1 <> " " <> show x2 <> "," <> show y2
+ <> "\" stroke=\"" <> renderObjectDataColor <> "\" stroke-width=\"3\" marker-end=\"url(#arrow)\">" <> renderObjectDataFullLabel <> " " <> "\n" <>
+ " show x <> "\" y=\"" <> show y <> "\" fill=\"" <> renderObjectDataColor <> "\" stroke=\"white\" stroke-width=\"10\" stroke-opacity=\".8\" paint-order=\"stroke\">" <> renderObjectDataLabel <> " "
+ | (edge, (((x1, y1), (x2, y2)), _)) <- edges
+ , Just RenderObjectData{..} <- [renderDataOf edge]
+ , let x = (x1 + x2) / 2
+ , let y = (y1 + y2) / 2 ]
+ , intercalate "\n"
+ [ " show x <> "\" y=\"" <> show y <> "\" fill=\"" <> renderObjectDataColor <> "\">" <> renderObjectDataLabel <> " "
+ | (v, ((x, y), _)) <- vertices
+ , Just RenderObjectData{..} <- [renderDataOf v]]
+ , " " ]
+ where
+ renderDataOf shapeId =
+ case renderDataOf' shapeId of
+ Nothing -> Nothing
+ Just RenderObjectData{..} -> Just RenderObjectData
+ -- FIXME: move constants to configurable parameters
+ { renderObjectDataLabel = hideWhenLargerThan shapeId 5 renderObjectDataLabel
+ , renderObjectDataFullLabel = limitLength 30 renderObjectDataFullLabel
+ , .. }
+
+ hideWhenLargerThan shapeId n s
+ | null s || length s > n = if '-' `elem` shapeId then "" else "•"
+ | otherwise = s
+
+ vertices =
+ [ (show x <> show y <> show z, ((500 * x'', 500 * y''), zIndex))
+ | x <- [0,1]
+ , y <- [0,1]
+ , z <- [0,1]
+ , let f c = 2 * fromInteger c - 1
+ , let x' = f x
+ , let y' = f (1-y)
+ , let z' = f z
+ , let ((x'', y''), zIndex) = point3Dto2D camera rotY (x', y', z') ]
+
+ radius = 20
+
+ mkEdge r (x1, y1) (x2, y2) = ((x1 + dx, y1 + dy), ((x2 - dx), (y2 - dy)))
+ where
+ d = sqrt ((x2 - x1)^2 + (y2 - y1)^2)
+ dx = r * (x2 - x1) / d
+ dy = r * (y2 - y1) / d
+
+ scaleAround (cx, cy) s (x, y) = (cx + s * (x - cx), cy + s * (y - cy))
+
+ mkFace (x1, y1) (x2, y2) (x3, y3) = (p1, p2, p3)
+ where
+ cx = (x1 + x2 + x3) / 3
+ cy = (y1 + y2 + y3) / 3
+ p1 = scaleAround (cx, cy) 0.85 (x1, y1)
+ p2 = scaleAround (cx, cy) 0.85 (x2, y2)
+ p3 = scaleAround (cx, cy) 0.85 (x3, y3)
+
+ edges =
+ [ (intercalate "-" [fromName, toName], (mkEdge radius from to, 0))
+ | (fromName, (from, _)) : vs <- tails vertices
+ , (toName, (to, _)) <- vs
+ , and (zipWith (<=) fromName toName)
+ ]
+
+ faces =
+ [ (intercalate "-" [name1, name2, name3], (mkFace v1 v2 v3, 0))
+ | (name1, (v1, _)) : vs <- tails vertices
+ , (name2, (v2, _)) : vs' <- tails vs
+ , and (zipWith (<=) name1 name2)
+ , (name3, (v3, _)) <- vs'
+ , and (zipWith (<=) name2 name3)
+ ]
+
+
+defaultCamera :: Floating a => Camera a
+defaultCamera = Camera
+ { cameraPos = (0, 7, 10)
+ , cameraAngleY = pi
+ , cameraAngleX = pi/5
+ , cameraFoV = pi/15
+ , cameraAspectRatio = 1
+ }