Skip to content
This repository has been archived by the owner on May 20, 2018. It is now read-only.

[WIP] Datatype descriptions #172

Open
wants to merge 78 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
bdd775a
Stub in a module of datatypes.
robrix Dec 13, 2015
9faf9c4
Datatype has a Datatype named Datatype.
robrix Dec 13, 2015
1b9853a
Add an `end` constructor.
robrix Dec 13, 2015
41b6e6d
Datatype is parameterized by an index type.
robrix Dec 13, 2015
4581153
Add a recursive case to Datatype.
robrix Dec 13, 2015
ff5228c
Add an argument case to Datatype.
robrix Dec 13, 2015
6c26495
Add the Datatype module to the directory.
robrix Dec 13, 2015
29e526a
Expand the error messages for the encoded Either tests.
robrix Dec 13, 2015
bca25eb
Stub in a private datatype-encoded boolean module.
robrix Dec 13, 2015
bc442ee
Test the equivalence of the datatype-encoded boolean module’s definit…
robrix Dec 13, 2015
75031d9
Pull the Datatype declaration into a temporary.
robrix Dec 13, 2015
744f3a6
Define everything in the datatype-encoded Boolean module.
robrix Dec 13, 2015
302b8d7
Merge branch 'master' into datatype-descriptions
robrix Dec 20, 2015
4c15906
Stub in a Tag module.
robrix Dec 20, 2015
cbf1f67
Add the tag module to the directory.
robrix Dec 20, 2015
dadb2f6
Tag depends on List.
robrix Dec 20, 2015
603450b
Tag depends on String.
robrix Dec 20, 2015
424fb14
Add an Enum type to the Tag module.
robrix Dec 20, 2015
a0affd6
The Datatype module depends on the Tag module.
robrix Dec 20, 2015
46f799f
Correct one of the stubbed in terms.
robrix Dec 20, 2015
994d78c
Define the Boolean enumeration.
robrix Dec 20, 2015
59c6443
Add a Tag binding.
robrix Dec 20, 2015
5ffd5be
Tags eliminate from their specific labels.
robrix Dec 21, 2015
447cc08
Add a `here` binding.
robrix Dec 21, 2015
a58bcbb
Eliminate Tag casewise.
robrix Dec 21, 2015
e37342c
Rename the label parameter.
robrix Dec 21, 2015
67a28f5
Add a `there` binding.
robrix Dec 21, 2015
e14213c
The false tag follows the true tag.
robrix Dec 21, 2015
aac26a7
Log the error messages more legibly.
robrix Dec 21, 2015
474ee0e
Log whether this is a type mismatch or a term mismatch.
robrix Dec 21, 2015
a148c43
Abstract a method to assert equivalent definitions.
robrix Dec 21, 2015
a6914f2
Pretty-print the actual values.
robrix Dec 21, 2015
32c70b7
Delegate the equivalence assertions.
robrix Dec 21, 2015
8b43b94
Test the equivalence of only the intersection.
robrix Dec 21, 2015
10abab0
Move the assertion into its own section.
robrix Dec 21, 2015
209d59a
Delegate all of the equivalences tests to the new assertion.
robrix Dec 21, 2015
b47ba76
Test only the intersection in the assertion.
robrix Dec 21, 2015
dedbd00
Add an assertion of the equivalence of two modules’ intersections.
robrix Dec 21, 2015
0f978ba
Delegate module equivalence assertions to the new assertion method.
robrix Dec 21, 2015
7f3239c
Merge branch 'master' into datatype-descriptions
robrix Dec 21, 2015
9e390a8
Formatting.
robrix Dec 21, 2015
2795353
Provide a definition of μ.
robrix Dec 21, 2015
ad71dd5
Stub in an `init` binding.
robrix Dec 21, 2015
866e1df
Add a declaration of `ISet`.
robrix Dec 21, 2015
e85717a
Rename ISet → IType, as it’s more in the zeitgeist.
robrix Dec 21, 2015
1e8fcb7
Datatype depends on PropositionalEquality.
robrix Dec 21, 2015
303e44f
Datatype depends on Pair.
robrix Dec 21, 2015
80e3f41
Datatype depends on Sigma.
robrix Dec 21, 2015
ad9bb65
Define `El` by eliminating datatypes.
robrix Dec 21, 2015
5bbcac4
El expects a type parameter.
robrix Dec 21, 2015
7d85abc
μ expects a type parameter.
robrix Dec 21, 2015
d09ee51
Test whether bindings are definitionally equal.
robrix Dec 21, 2015
354e939
Remove a use of IType.
robrix Dec 21, 2015
aef38ef
Revert "Remove a use of IType."
robrix Dec 21, 2015
cf4ddca
Use `IType` a bit more widely.
robrix Dec 21, 2015
18ab314
Remove unnecessary parens.
robrix Dec 21, 2015
933cfde
Stub in some more of the definition of `init`.
robrix Dec 21, 2015
61e9337
Typecheck the datatype-encoded booleans.
robrix Dec 21, 2015
e97a3ba
Inline the enumeration of boolean case names.
robrix Dec 21, 2015
0727b6f
µ → μ.
robrix Dec 21, 2015
f3cd0ff
Stub in a `Branches` binding.
robrix Dec 23, 2015
9350cb8
here/there expect more parameters.
robrix Dec 23, 2015
0fa4711
The first argument apparently needs to be `List String` instead of `E…
robrix Dec 23, 2015
8ecda22
Stub in a `case` definition.
robrix Dec 23, 2015
a31a773
Type the first argument to `case` as `List String`.
robrix Dec 23, 2015
ba11f55
Stub in the value for `case`.
robrix Dec 23, 2015
1aa1459
Reduce the annotation.
robrix Dec 23, 2015
8b7dabd
Spacing.
robrix Dec 23, 2015
63aff41
Type the enumerations as Enum.
robrix Dec 23, 2015
edee946
Correct the definitions of first & second.
robrix Dec 23, 2015
33751b4
Attempt to elaborate the types of applications against a lambda type.
robrix Dec 23, 2015
c41c4d9
Add a `firstBranch` binding to eliminate values in `Branches`.
robrix Dec 25, 2015
1bcfb02
Add a `secondBranch` binding.
robrix Dec 25, 2015
161d750
Define `case` in terms of `firstBranch`.
robrix Dec 25, 2015
c7b260a
Define `case` in terms of `secondBranch`.
robrix Dec 25, 2015
7fb9b25
Merge branch 'master' into datatype-descriptions
robrix Jan 1, 2016
b249859
Indicate value mismatches with =.
robrix Jan 1, 2016
31b80bc
Use the Term.equate method.
robrix Jan 1, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Manifold.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
D470CB981BDC27130003A931 /* Module+Vector.swift in Sources */ = {isa = PBXBuildFile; fileRef = D470CB971BDC27130003A931 /* Module+Vector.swift */; };
D4809FBD1AF6BD400084B8FE /* TermTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4809FBC1AF6BD400084B8FE /* TermTests.swift */; };
D484903C1B2A40E800F249F7 /* EvaluationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D484903B1B2A40E800F249F7 /* EvaluationTests.swift */; };
D492927B1C26837000BA59F3 /* Module+Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D492927A1C26837000BA59F3 /* Module+Tag.swift */; };
D492927F1C278CC000BA59F3 /* Module+PropositionalEquality.swift in Sources */ = {isa = PBXBuildFile; fileRef = D492927E1C278CC000BA59F3 /* Module+PropositionalEquality.swift */; };
D4A31B2A1AA366EC00B3FC68 /* TermContainerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A31B291AA366EC00B3FC68 /* TermContainerType.swift */; };
D4ACE90D1BDC7E51009E928F /* Module+FiniteSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4ACE90C1BDC7E51009E928F /* Module+FiniteSet.swift */; };
Expand Down Expand Up @@ -53,6 +54,7 @@
D4F969981B98F3220069F481 /* Term+Arbitrary.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4F969971B98F3220069F481 /* Term+Arbitrary.swift */; };
D4F9F86B1A8496F700B7071E /* Prelude.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4F9F86A1A8496F700B7071E /* Prelude.framework */; };
D4F9F86C1A84970900B7071E /* Prelude.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4F9F86A1A8496F700B7071E /* Prelude.framework */; };
D4FA652D1C1CF228009999A3 /* Module+Datatype.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FA652C1C1CF228009999A3 /* Module+Datatype.swift */; };
D4FB02D91B71D06A0090E764 /* Module+Boolean.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FB02D81B71D06A0090E764 /* Module+Boolean.swift */; };
D4FB2D071BE447DE00B3CCE0 /* Module+Directory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FB2D061BE447DE00B3CCE0 /* Module+Directory.swift */; };
D4FB2D091BE4490000B3CCE0 /* ModuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4FB2D081BE4490000B3CCE0 /* ModuleTests.swift */; };
Expand Down Expand Up @@ -88,6 +90,7 @@
D470CB971BDC27130003A931 /* Module+Vector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Module+Vector.swift"; sourceTree = "<group>"; };
D4809FBC1AF6BD400084B8FE /* TermTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TermTests.swift; sourceTree = "<group>"; };
D484903B1B2A40E800F249F7 /* EvaluationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EvaluationTests.swift; sourceTree = "<group>"; };
D492927A1C26837000BA59F3 /* Module+Tag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Module+Tag.swift"; sourceTree = "<group>"; };
D492927E1C278CC000BA59F3 /* Module+PropositionalEquality.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Module+PropositionalEquality.swift"; sourceTree = "<group>"; };
D4A31B291AA366EC00B3FC68 /* TermContainerType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TermContainerType.swift; sourceTree = "<group>"; };
D4ACE90C1BDC7E51009E928F /* Module+FiniteSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Module+FiniteSet.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -119,6 +122,7 @@
D4F969951B98ECE80069F481 /* SwiftCheck.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SwiftCheck.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D4F969971B98F3220069F481 /* Term+Arbitrary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Term+Arbitrary.swift"; sourceTree = "<group>"; };
D4F9F86A1A8496F700B7071E /* Prelude.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Prelude.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D4FA652C1C1CF228009999A3 /* Module+Datatype.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Module+Datatype.swift"; sourceTree = "<group>"; };
D4FB02D81B71D06A0090E764 /* Module+Boolean.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Module+Boolean.swift"; sourceTree = "<group>"; };
D4FB2D061BE447DE00B3CCE0 /* Module+Directory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Module+Directory.swift"; sourceTree = "<group>"; };
D4FB2D081BE4490000B3CCE0 /* ModuleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModuleTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -240,6 +244,8 @@
isa = PBXGroup;
children = (
D445417B1BCAB0C100F2946D /* Module+Unit.swift */,
D4FA652C1C1CF228009999A3 /* Module+Datatype.swift */,
D492927A1C26837000BA59F3 /* Module+Tag.swift */,
D4FB02D81B71D06A0090E764 /* Module+Boolean.swift */,
D445417F1BCAC38500F2946D /* Module+List.swift */,
D4E101B91B484611001A7E55 /* Module+Natural.swift */,
Expand Down Expand Up @@ -365,6 +371,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D492927B1C26837000BA59F3 /* Module+Tag.swift in Sources */,
D445417C1BCAB0C100F2946D /* Module+Unit.swift in Sources */,
D4E9901C1BD3431D00F00CA7 /* Module+Either.swift in Sources */,
D43B6D1B1C1DB2CA008EF3D2 /* Module+String.swift in Sources */,
Expand All @@ -382,6 +389,7 @@
D4A31B2A1AA366EC00B3FC68 /* TermContainerType.swift in Sources */,
D44541801BCAC38500F2946D /* Module+List.swift in Sources */,
D463F6D21BD2A83E00BA0628 /* Module+Maybe.swift in Sources */,
D4FA652D1C1CF228009999A3 /* Module+Datatype.swift in Sources */,
D4E990241BD3EE5300F00CA7 /* AnnotatedTerm.swift in Sources */,
D4FB2D0B1BE44DAF00B3CCE0 /* Module+Functor.swift in Sources */,
D445418E1BCAF57D00F2946D /* Term+Evaluation.swift in Sources */,
Expand Down
46 changes: 46 additions & 0 deletions Manifold/Module+Datatype.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright © 2015 Rob Rix. All rights reserved.

extension Module {
public static var datatype: Module {
let _Datatype: Term = "Datatype"
let datatype = Declaration("Datatype", Datatype("I", .Type,
[
"end": .Argument("index", "I", .End),
"recursive": .Argument("index", "I", .Recursive("recur", .End)),
"argument": Telescope.Argument("A", .Type, .Argument("telescope", "A" --> _Datatype["I" as Term], .End)),
]
))

let μ = Declaration("μ",
type: nil => { I in _Datatype[I] --> I --> .Type },
value: nil => { I in (_Datatype[I], I, .Type) => { _, _, Motive in (_Datatype[I] --> I --> Motive) --> Motive } })

let IType = Declaration("IType",
type: .Type --> .Type(1),
value: .Type => { I in I --> .Type })

let Identical: Term = "≡"
let Pair: Term = "Pair"
let Sigma: Term = "Sigma"
let El: Term = "El"
let el = Declaration("El",
type: .Type => { I in _Datatype[I] --> IType.ref[I] --> IType.ref[I] },
value: .Type => { I in
(_Datatype[I], IType.ref[I], I) => { D, X, i in
D[.Type,
I => { j in Identical[I, i, j] },
(I, _Datatype[I]) => { j, D in Pair[X[j], El[I, D, X, i]] },
.Type => { A in (A --> _Datatype[I]) => { B in Sigma[A, nil => { a in El[I, B[a], X, i] }] } }]
}
})

let `init` = Declaration("init",
type: nil => { I in (_Datatype[I], I) => { D, i in El[I, D, μ.ref[I, D], i] --> μ.ref[I, D, i] } },
value: nil => { I in (nil, nil) => { D, i in nil => { _ in nil } } })

return Module("Datatype", [ tag, propositionalEquality, pair, sigma ], [ datatype, μ, `init`, IType, el ])
}
}


import Prelude
2 changes: 2 additions & 0 deletions Manifold/Module+Directory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ extension Module {
vector,
finiteSet,
string,
datatype,
tag,
].map { ($0.name, $0) })
}
8 changes: 4 additions & 4 deletions Manifold/Module+Pair.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ extension Module {
))

let first = Declaration("first",
type: (nil, nil) => { A, B in Pair.ref[A, B] --> A },
value: (nil, nil, nil) => { A, B, pair in pair[nil, (nil, B) => { a, _ in a }] })
type: (.Type, .Type) => { A, B in Pair.ref[A, B] --> A },
value: (nil, nil) => { A, B in nil => { pair in pair[nil, (nil, B) => { a, _ in a }] } })

let second = Declaration("second",
type: (nil, nil) => { A, B in Pair.ref[A, B] --> B },
value: (nil, nil, nil) => { A, B, pair in pair[nil, (nil, nil) => { _, b in b }] })
type: (.Type, .Type) => { A, B in Pair.ref[A, B] --> B },
value: (nil, nil) => { A, B in nil => { pair in pair[nil, (nil, nil) => { _, b in b }] } })

return Module("Pair", [ Pair, first, second ])
}
Expand Down
48 changes: 48 additions & 0 deletions Manifold/Module+Tag.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright © 2015 Rob Rix. All rights reserved.

extension Module {
public static var tag: Module {
let List: Term = "List"
let cons: Term = "cons"
let String: Term = "String"
let Enum = Declaration("Enum",
type: .Type,
value: List[String])

let Tag = Declaration("Tag",
type: Enum.ref --> .Type,
value: (Enum.ref, .Type) => { e, Motive in (String --> Motive) --> (List[String] --> Motive) --> Motive })

let here = Declaration("here",
type: (String, List[String]) => { l, E in Tag.ref[cons[nil, l, E]] },
value: (String, List[String], .Type) => { l, _, Motive in (String --> Motive, List[String] --> Motive) => { f, _ in f[l] } })

let there = Declaration("there",
type: (String, List[String]) => { l, E in Tag.ref[E] --> Tag.ref[cons[nil, l, E]] },
value: (String, List[String]) => { _, E in Tag.ref[E] --> .Type => { Motive in (String --> Motive, List[String] --> Motive) => { _, f in f[E] } } })

let Unit: Term = "Unit"
let Pair: Term = "Pair"
let Branches: Term = "Branches"
let branches = Declaration("Branches",
type: Enum.ref => { E in (Tag.ref[E] --> .Type) --> .Type },
value: nil => { E in nil => { P in E[nil, (nil, nil) => { l, E in Pair[P[here.ref[nil, nil]], Branches[E, nil => { t in P[there.ref[nil, nil, t]] }]] }, Unit] } })

let first: Term = "first"
let firstBranch = Declaration("firstBranch",
type: (String, Enum.ref) => { l, E in (Tag.ref[cons[String, l, E]] --> .Type) => { P in Branches[cons[String, l, E], P] => { cs in P[here.ref[l, E]] } } },
value: (String, Enum.ref) => { l, E in (Tag.ref[cons[String, l, E]] --> .Type) => { P in Branches[cons[String, l, E], P] => { cs in first[nil, nil, cs] } } })

let second: Term = "second"
let secondBranch = Declaration("secondBranch",
type: (String, Enum.ref) => { l, E in (Tag.ref[cons[String, l, E]] --> .Type) => { P in Branches[cons[String, l, E], P] => { cs in P[there.ref[l, E, here.ref[nil, nil]]] } } },
value: (String, Enum.ref) => { l, E in (Tag.ref[cons[String, l, E]] --> .Type) => { P in Branches[cons[String, l, E], P] => { cs in second[nil, nil, cs] } } })

let _case: Term = "case"
let `case` = Declaration("case",
type: Enum.ref => { E in (Tag.ref[E] --> .Type) => { P in Branches[E, P] --> Tag.ref[E] => { t in P[t] } } },
value: nil => { E in nil => { P in (nil, nil) => { cs, t in t[nil, nil => { _ in firstBranch.ref[nil, nil, P, cs] }, nil => { t in _case[E, nil => { t in P[E, there.ref[nil, nil, t]] }, secondBranch.ref[nil, nil, P, cs], t] }] } } })

return Module("Tag", [ list, string, unit, pair ], [ Enum, Tag, here, there, branches, firstBranch, secondBranch, `case` ])
}
}
4 changes: 2 additions & 2 deletions Manifold/Term+Elaboration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ extension Term {
return .Unroll(type, .Variable(name))

case let (.Identity(.Application(a, b)), .Identity(.Implicit)):
let aʹ = try a.elaborateType(nil, environment, context)
let aʹ = try a.elaborateType(nil --> nil, environment, context)
guard case let .Identity(.Lambda(type, body)) = aʹ.annotation.weakHeadNormalForm(environment).out else {
throw "Illegal application of \(a) : \(aʹ.annotation) in context: \(Term.toString(context, separator: ":")), environment: \(Term.toString(environment, separator: "="))"
}
Expand Down Expand Up @@ -60,7 +60,7 @@ extension Term {

case let (_, b):
let a = try elaborateType(nil, environment, context)
guard Term.equate(a.annotation, Term(b), environment) != nil else {
guard Term.equate(a.annotation.weakHeadNormalForm(environment), Term(b), environment) != nil else {
throw "Type mismatch: expected '\(self)' to be of type '\(Term(b))', but it was actually of type '\(a.annotation)' in context: \(Term.toString(context, separator: ":")), environment: \(Term.toString(environment, separator: "="))"
}
return a
Expand Down
112 changes: 92 additions & 20 deletions ManifoldTests/ModuleTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ final class ModuleTests: XCTestCase {
// MARK: Boolean

func testEquivalenceOfEncodedAndDatatypeBooleans() {
encodedBoolean.definitions.forEach { symbol, type, value in
assert(Module.boolean.context[symbol], Term.equate, type, message: "\(symbol)")
assert(Module.boolean.environment[symbol], Term.equate, value, message: "\(symbol)")
}
assertEquivalent(encodedBoolean, Module.boolean)
}


Expand All @@ -32,40 +29,28 @@ final class ModuleTests: XCTestCase {
// MARK: Pair

func testEquivalenceOfEncodedAndDatatypePairs() {
encodedPair.definitions.forEach { symbol, type, value in
assert(Module.pair.context[symbol], Term.equate, type, message: "\(symbol)")
assert(Module.pair.environment[symbol], Term.equate, value, message: "\(symbol)")
}
assertEquivalent(encodedPair, Module.pair)
}


// MARK: Sigma

func testEquivalenceOfEncodedAndDatatypeSigmas() {
encodedSigma.definitions.forEach { symbol, type, value in
assert(Module.sigma.context[symbol], Term.equate, type, message: "'\(symbol)' expected '\(type)', actual '\(Module.sigma.context[symbol])'")
assert(Module.sigma.environment[symbol], Term.equate, value, message: "'\(symbol)'\nexpected '\(value)'\nactual '\(Module.sigma.environment[symbol] ?? "nil")'")
}
assertEquivalent(encodedSigma, Module.sigma)
}


// MARK: Either

func testEquivalenceOfEncodedAndDatatypeEithers() {
Module.either.definitions.forEach { symbol, type, value in
assert(encodedEither.context[symbol], Term.equate, type, message: "\(symbol)")
assert(encodedEither.environment[symbol], Term.equate, value, message: "\(symbol)")
}
assertEquivalent(encodedEither, Module.either)
}


// MARK: List

func testEquivalenceOfEncodedAndDatatypeLists() {
encodedList.definitions.forEach { symbol, type, value in
assert(Module.list.context[symbol], Term.equate, type, message: "'\(symbol)' expected '\(type)', actual '\(Module.list.context[symbol])'")
assert(Module.list.environment[symbol], Term.equate, value, message: "'\(symbol)' expected '\(value)', actual '\(Module.list.environment[symbol])'")
}
assertEquivalent(encodedList, Module.list)
}

func testListValuesAsEliminators() {
Expand Down Expand Up @@ -115,6 +100,37 @@ final class ModuleTests: XCTestCase {
assert(try term.elaborateType("String", environment, Module.string.context).annotation, Term.equate, "String")
assert(try term.evaluate(environment), Term.equate, Term.Embedded("hi", "String"))
}


// MARK: Datatype

func testEquivalenceOfDatatypeEncodedAndDatatypeBooleans() {
datatypeEncodedBoolean.typecheck().forEach { XCTFail($0) }
assertEquivalent(datatypeEncodedBoolean, Module.boolean)
}


// MARK: Assertions

func assertEquivalent(a: Module, _ b: Module, _ file: String = __FILE__, _ line: UInt = __LINE__) {
a.definitions.forEach { definition in assertEquivalent(definition, b, file, line) }
}

func assertEquivalent(definition: (Name, Term, Term), _ module: Module, _ file: String = __FILE__, _ line: UInt = __LINE__) {
let (symbol, type, value) = definition
if let actual = module.context[symbol] {
assert(actual, Term.equate, type, message:
"Type mismatch in '\(module.name).\(symbol)'\n"
+ "expected : \(type)\n"
+ " actual : \(actual)\n", file: file, line: line)
}
if let actual = module.environment[symbol] {
assert(actual, Term.equate, value, message:
"Term mismatch in '\(module.name).\(symbol)'\n"
+ "expected = \(value)\n"
+ " actual = \(actual)\n", file: file, line: line)
}
}
}


Expand Down Expand Up @@ -203,6 +219,62 @@ private let encodedList: Module = {
private let embedCharacter: Character -> Term = { Term.Embedded($0, "Character") }


private let datatypeEncodedBoolean: Module = {
let Enum: Term = "Enum"
let cons: Term = "cons"
let `nil`: Term = "nil"
let Tag: Term = "Tag"
let here: Term = "here"
let there: Term = "there"
let Datatype: Term = "Datatype"
let argument: Term = "argument"
let end: Term = "end"
let μ: Term = "μ"
let caseD: Term = "caseD"
let `init`: Term = "init"
let refl: Term = "refl"
let Unit: Term = "Unit"
let unit: Term = "unit"
let String: Term = "String"

let embedString: Swift.String -> Term = { .Embedded($0, String) }

let BooleanT = Declaration("BooleanT",
type: .Type,
value: Tag[cons[nil, embedString("true"), cons[nil, embedString("false"), `nil`[Term.Implicit]]]])

let BooleanC = Declaration("BooleanC",
type: BooleanT.ref --> Datatype[Unit],
value: caseD[end[unit], end[unit]])

let BooleanD = Declaration("BooleanD",
type: Datatype[Unit],
value: argument[BooleanT.ref, BooleanC.ref])

let Boolean = Declaration("Boolean",
type: .Type,
value: μ[BooleanD.ref])

let trueT = Declaration("trueT",
type: BooleanT.ref,
value: here)

let `true` = Declaration("true",
type: Boolean.ref,
value: `init`[trueT.ref, refl])

let falseT = Declaration("falseT",
type: BooleanT.ref,
value: there[here])

let `false` = Declaration("false",
type: Boolean.ref,
value: `init`[falseT.ref, refl])

return Module("DatatypeEncodedBoolean", [ Module.unit, Module.datatype ], [ BooleanT, BooleanC, BooleanD, Boolean, trueT, `true`, falseT, `false` ])
}()


import Assertions
@testable import Manifold
import Prelude
Expand Down