diff --git a/src/categorical_algebra/CSetDataStructures.jl b/src/categorical_algebra/CSetDataStructures.jl
index d475d670a..bf98a4759 100644
--- a/src/categorical_algebra/CSetDataStructures.jl
+++ b/src/categorical_algebra/CSetDataStructures.jl
@@ -604,8 +604,9 @@ function Base.show(io::IO, acs::T) where {S,T<:StructACSet{S}}
s = SchemaDesc(S)
if get(io, :compact, false)
print(io, nameof(T))
- print(io, ": ")
+ print(io, " {")
join(io, ("$ob = $(nparts(acs,ob))" for ob in s.obs), ", ")
+ print(io, "}")
else
print(io, T)
println(io, ":")
diff --git a/src/categorical_algebra/CSets.jl b/src/categorical_algebra/CSets.jl
index 76a8c6c58..f13b8d33a 100644
--- a/src/categorical_algebra/CSets.jl
+++ b/src/categorical_algebra/CSets.jl
@@ -253,6 +253,14 @@ type_components(α::TightACSetTransformation{S}) where S =
map_components(f, α::TightACSetTransformation) =
TightACSetTransformation(map(f, components(α)), dom(α), codom(α))
+function Base.show(io::IO, α::TightACSetTransformation)
+ print(io, "ACSetTransformation(")
+ show(io, components(α))
+ print(io, ", ")
+ Categories.show_domains(io, α)
+ print(io, ")")
+end
+
""" Loose transformation between attributed C-sets.
See [`ACSetTranformation`](@ref) for the distinction between tight and loose.
@@ -308,6 +316,14 @@ function Base.getindex(α::LooseACSetTransformation, c::Symbol)
end
end
+function Base.show(io::IO, α::LooseACSetTransformation)
+ print(io, "ACSetTransformation(")
+ show(io, merge(components(α), type_components(α)))
+ print(io, ", ")
+ Categories.show_domains(io, α)
+ print(io, ")")
+end
+
function is_natural(α::ACSetTransformation{S}) where {S}
X, Y = dom(α), codom(α)
for (f, c, d) in flatten((zip(hom(S), dom(S), codom(S)),
diff --git a/src/categorical_algebra/Categories.jl b/src/categorical_algebra/Categories.jl
index d971ccff6..98afd4800 100644
--- a/src/categorical_algebra/Categories.jl
+++ b/src/categorical_algebra/Categories.jl
@@ -88,6 +88,9 @@ TypeCat(Ob::Type, Hom::Type) = TypeCat{Ob,Hom}()
#ob(::TypeCat{Ob,Hom}, x) where {Ob,Hom} = convert(Ob, x)
#hom(::TypeCat{Ob,Hom}, f) where {Ob,Hom} = convert(Hom, f)
+Base.show(io::IO, ::TypeCat{Ob,Hom}) where {Ob,Hom} =
+ print(io, "TypeCat($Ob, $Hom)")
+
# Functors
##########
@@ -119,6 +122,26 @@ codom(F::IdentityFunctor) = F.dom
do_ob_map(F::IdentityFunctor, x) = ob(F.dom, x)
do_hom_map(F::IdentityFunctor, f) = hom(F.dom, f)
+function Base.show(io::IO, F::IdentityFunctor)
+ print(io, "id(")
+ show_domains(io, F, codomain=false)
+ print(io, ")")
+end
+
+show_type_constructor(io::IO, ::Type{<:Functor}) = print(io, "Functor")
+
+function show_domains(io::IO, f; codomain::Bool=true, recurse::Bool=true)
+ if get(io, :hide_domains, false)
+ print(io, "…")
+ else
+ show(IOContext(io, :compact=>true, :hide_domains=>!recurse), dom(f))
+ if codomain
+ print(io, ", ")
+ show(IOContext(io, :compact=>true, :hide_domains=>!recurse), codom(f))
+ end
+ end
+end
+
# Instances
#----------
diff --git a/src/categorical_algebra/FinCats.jl b/src/categorical_algebra/FinCats.jl
index f64a0710f..0df67a725 100644
--- a/src/categorical_algebra/FinCats.jl
+++ b/src/categorical_algebra/FinCats.jl
@@ -75,6 +75,14 @@ graph(C::FinCatGraph) = C.graph
ob_generators(C::FinCatGraph) = vertices(graph(C))
hom_generators(C::FinCatGraph) = edges(graph(C))
+function Base.show(io::IO, C::FinCatGraph)
+ print(io, "FinCat(")
+ show(io, graph(C))
+ print(io, ", [")
+ join(io, equations(C), ", ")
+ print(io, "])")
+end
+
# Paths in graphs
#----------------
@@ -114,6 +122,12 @@ function Base.vcat(p1::Path, p2::Path)
Path(vcat(edges(p1), edges(p2)), src(p1), tgt(p2))
end
+function Base.show(io::IO, path::Path)
+ print(io, "Path(")
+ show(io, edges(path))
+ print(io, ": $(src(path)) → $(tgt(path)))")
+end
+
""" Abstract type for category whose morphisms are paths in a graph.
(Or equivalence classes of paths in a graph, but we compute with
@@ -152,6 +166,12 @@ FinCatGraph(g::HasGraph) = FreeCatGraph(g)
is_free(::FreeCatGraph) = true
+function Base.show(io::IO, C::FreeCatGraph)
+ print(io, "FinCat(")
+ show(io, graph(C))
+ print(io, ")")
+end
+
# Category on graph with equations
#---------------------------------
@@ -228,6 +248,12 @@ hom(C::FinCatPresentation{Schema}, f::GATExpr) =
gat_typeof(f) ∈ (:Hom, :Attr) ? f :
error("Expression $f is not a morphism or attribute")
+function Base.show(io::IO, C::FinCatPresentation)
+ print(io, "FinCat(")
+ show(io, presentation(C))
+ print(io, ")")
+end
+
# Functors
##########
@@ -256,6 +282,9 @@ end
(F::FinDomFunctor)(expr::ObExpr) = ob_map(F, expr)
(F::FinDomFunctor)(expr::HomExpr) = hom_map(F, expr)
+Categories.show_type_constructor(io::IO, ::Type{<:FinDomFunctor}) =
+ print(io, "FinDomFunctor")
+
""" Is the purported functor on a presented category functorial?
This function checks that functor preserves domains and codomains. When
@@ -291,6 +320,9 @@ FinFunctor(ob_map, hom_map, dom::FinCat, codom::FinCat) =
FinFunctor(ob_map, hom_map, dom::Presentation, codom::Presentation) =
FinDomFunctor(ob_map, hom_map, FinCat(dom), FinCat(codom))
+Categories.show_type_constructor(io::IO, ::Type{<:FinFunctor}) =
+ print(io, "FinFunctor")
+
# Mapping-based functors
#-----------------------
@@ -328,25 +360,23 @@ functor_key(C::FinCat, expr::GATExpr) = head(expr) == :generator ?
Categories.do_ob_map(F::FinDomFunctorMap, x) = F.ob_map[x]
Categories.do_hom_map(F::FinDomFunctorMap, f) = F.hom_map[f]
+collect_ob(F::FinDomFunctorMap) = values(F.ob_map)
+collect_hom(F::FinDomFunctorMap) = values(F.hom_map)
+
function Categories.do_compose(F::FinDomFunctorMap, G::FinDomFunctorMap)
FinDomFunctorMap(mapvals(x -> ob_map(G, x), F.ob_map),
mapvals(f -> hom_map(G, f), F.hom_map), dom(F), codom(G))
end
-""" Functor object and morphism maps given as vectors.
-"""
-const FinDomFunctorVector{Dom<:FinCat,Codom<:Cat,
- ObMap<:AbstractVector,HomMap<:AbstractVector} =
- FinDomFunctorMap{Dom,Codom,ObMap,HomMap}
-
-collect_ob(F::FinDomFunctorVector) = F.ob_map
-collect_hom(F::FinDomFunctorVector) = F.hom_map
-
-""" Functor with object and morphism maps given as dictionaries.
-"""
-const FinDomFunctorDict{Dom<:FinCat,Codom<:Cat,
- ObMap<:AbstractDict,HomMap<:AbstractDict} =
- FinDomFunctorMap{Dom,Codom,ObMap,HomMap}
+function Base.show(io::IO, F::T) where T <: FinDomFunctorMap
+ Categories.show_type_constructor(io, T); print(io, "(")
+ show(io, F.ob_map)
+ print(io, ", ")
+ show(io, F.hom_map)
+ print(io, ", ")
+ Categories.show_domains(io, F)
+ print(io, ")")
+end
# Natural transformations
#########################
@@ -431,11 +461,8 @@ transformation_key(C::FinCat, x) = x
transformation_key(C::FinCat, expr::GATExpr) = head(expr) == :generator ?
first(expr) : error("Natural transformation must be defined on generators")
-component(α::FinTransformationMap{C,D,F,G,Comp}, c::Integer) where
- {C,D,F,G,Comp<:AbstractVector} = α.components[c]
-component(α::FinTransformationMap{C,D,F,G,Comp}, c::Key) where
- {Key,C,D,F,G,Comp<:AbstractDict{Key}} = α.components[c]
-component(α::FinTransformationMap, expr::GATExpr) =
+component(α::FinTransformationMap, x) = α.components[x]
+component(α::FinTransformationMap, expr::GATExpr{:generator}) =
component(α, first(expr))
function Categories.do_compose(α::FinTransformationMap, β::FinTransformation)
@@ -458,6 +485,16 @@ function Categories.do_composeH(α::FinTransformationMap, H::Functor)
compose(F, H), compose(G, H))
end
+function Base.show(io::IO, α::FinTransformationMap)
+ print(io, "FinTransformation(")
+ show(io, components(α))
+ print(io, ", ")
+ Categories.show_domains(io, α, recurse=false)
+ print(io, ", ")
+ Categories.show_domains(io, dom(α))
+ print(io, ")")
+end
+
# Dict utilities
################
diff --git a/src/categorical_algebra/FinSets.jl b/src/categorical_algebra/FinSets.jl
index 080226aa3..e0171a9c3 100644
--- a/src/categorical_algebra/FinSets.jl
+++ b/src/categorical_algebra/FinSets.jl
@@ -71,7 +71,11 @@ Base.iterate(set::FinSetCollection, args...) = iterate(set.collection, args...)
Base.length(set::FinSetCollection) = length(set.collection)
Base.in(set::FinSetCollection, elem) = in(elem, set.collection)
-Base.show(io::IO, set::FinSetCollection) = print(io, "FinSet($(set.collection)")
+function Base.show(io::IO, set::FinSetCollection)
+ print(io, "FinSet(")
+ show(io, set.collection)
+ print(io, ")")
+end
""" Finite set whose elements are rows of a table.
@@ -86,7 +90,11 @@ FinSet(nt::NamedTuple) = TabularSet(nt)
Base.iterate(set::TabularSet, args...) = iterate(Tables.rows(set.table), args...)
Base.length(set::TabularSet) = Tables.rowcount(set.table)
-Base.show(io::IO, set::TabularSet) = print(io, "TabularSet($(set.table))")
+function Base.show(io::IO, set::TabularSet)
+ print(io, "TabularSet(")
+ show(io, set.table)
+ print(io, ")")
+end
function Base.show(io::IO, ::MIME"text/plain", set::TabularSet{T}) where T
print(io, "$(length(set))-element TabularSet{$T}")
@@ -96,6 +104,14 @@ function Base.show(io::IO, ::MIME"text/plain", set::TabularSet{T}) where T
end
end
+function Base.show(io::IO, ::MIME"text/html", set::TabularSet)
+ println(io, "
")
+ println(io, "$(length(set))-element TabularSet")
+ PrettyTables.pretty_table(io, set.table, backend=Val(:html), standalone=false,
+ nosubheader=true)
+ println(io, "
")
+end
+
# Discrete categories
#--------------------
@@ -128,6 +144,9 @@ FinDomFunctor(ob_map, ::Nothing, dom::DiscreteCat, codom::Cat) =
hom_map(F::FinDomFunctor{<:DiscreteCat}, x) = id(codom(F), ob_map(F, x))
+Base.show(io::IO, C::DiscreteCat{Int,FinSetInt}) =
+ print(io, "FinCat($(length(C.set)))")
+
# Finite functions
##################
@@ -158,7 +177,8 @@ function FinFunction(f::AbstractVector{Int}, args...; index=false)
end
end
-Sets.show_type(io::IO, ::Type{<:FinFunction}) = print(io, "FinFunction")
+Sets.show_type_constructor(io::IO, ::Type{<:FinFunction}) =
+ print(io, "FinFunction")
""" Function out of a finite set.
@@ -180,7 +200,8 @@ function FinDomFunction(f::AbstractVector, args...; index=false)
end
end
-Sets.show_type(io::IO, ::Type{<:FinDomFunction}) = print(io, "FinDomFunction")
+Sets.show_type_constructor(io::IO, ::Type{<:FinDomFunction}) =
+ print(io, "FinDomFunction")
""" Function in **Set** represented by a vector.
@@ -206,8 +227,11 @@ dom(f::FinDomFunctionVector) = FinSet(length(f.func))
(f::FinDomFunctionVector)(x) = f.func[x]
-Base.show(io::IO, f::FinDomFunctionVector) =
- print(io, "FinDomFunction($(f.func), $(dom(f)), $(codom(f)))")
+function Base.show(io::IO, f::FinDomFunctionVector)
+ print(io, "FinDomFunction($(f.func), ")
+ Sets.show_domains(io, f)
+ print(io, ")")
+end
""" Force evaluation of lazy function or relation.
"""
@@ -232,7 +256,7 @@ Sets.do_compose(f::FinFunctionVector, g::FinDomFunctionVector) =
@cocartesian_monoidal_instance FinSet FinFunction
Ob(C::FinCat{Int}) = FinSet(length(ob_generators(C)))
-Ob(F::FinCats.FinDomFunctorVector) = FinDomFunction(F.ob_map, Ob(codom(F)))
+Ob(F::Functor{<:FinCat{Int}}) = FinDomFunction(collect_ob(F), Ob(codom(F)))
# Indexed functions
#------------------
@@ -268,8 +292,11 @@ Base.:(==)(f::Union{FinDomFunctionVector,IndexedFinDomFunction},
# Ignore index when comparing for equality.
f.func == g.func && codom(f) == codom(g)
-Base.show(io::IO, f::IndexedFinDomFunction) =
- print(io, "FinDomFunction($(f.func), $(dom(f)), $(codom(f)), index=true)")
+function Base.show(io::IO, f::IndexedFinDomFunction)
+ print(io, "FinDomFunction($(f.func), ")
+ Sets.show_domains(io, f)
+ print(io, ", index=true)")
+end
dom(f::IndexedFinDomFunction) = FinSet(length(f.func))
force(f::IndexedFinDomFunction) = f
diff --git a/src/categorical_algebra/Sets.jl b/src/categorical_algebra/Sets.jl
index e4d4c08a2..6ea41e2d4 100644
--- a/src/categorical_algebra/Sets.jl
+++ b/src/categorical_algebra/Sets.jl
@@ -14,6 +14,7 @@ using FunctionWrappers: FunctionWrapper
using ...GAT, ..Categories, ..FreeDiagrams, ..Limits
using ...Theories: Category
import ...Theories: Ob, dom, codom, id, compose, ⋅, ∘
+import ..Categories: show_type_constructor, show_domains
import ..Limits: limit, universal
# Data types
@@ -52,7 +53,7 @@ abstract type SetFunction{Dom <: SetOb, Codom <: SetOb} end
SetFunction(f::Function, args...) = SetFunctionCallable(f, args...)
SetFunction(::typeof(identity), args...) = SetFunctionIdentity(args...)
-show_type(io::IO, ::Type{<:SetFunction}) = print(io, "SetFunction")
+show_type_constructor(io::IO, ::Type{<:SetFunction}) = print(io, "SetFunction")
""" Function in **Set** defined by a callable Julia object.
"""
@@ -75,8 +76,10 @@ end
function Base.show(io::IO, f::F) where F <: SetFunctionCallable
func = f.func.obj[] # Deference FunctionWrapper
- show_type(io, F)
- print(io, "($(nameof(func)), $(f.dom), $(f.codom))")
+ show_type_constructor(io, F)
+ print(io, "($(nameof(func)), ")
+ show_domains(io, f)
+ print(io, ")")
end
""" Identity function in **Set**.
@@ -95,8 +98,9 @@ codom(f::SetFunctionIdentity) = f.dom
(f::SetFunctionIdentity)(x) = x
function Base.show(io::IO, f::F) where F <: SetFunctionIdentity
- show_type(io, F)
- print(io, "(identity, $(f.dom))")
+ print(io, "id(")
+ show_domains(io, f, codomain=false)
+ print(io, ")")
end
""" Function in **Set** taking a constant value.
diff --git a/test/categorical_algebra/CSetDataStructures.jl b/test/categorical_algebra/CSetDataStructures.jl
index ef02175ac..3d620ce2b 100644
--- a/test/categorical_algebra/CSetDataStructures.jl
+++ b/test/categorical_algebra/CSetDataStructures.jl
@@ -77,22 +77,22 @@ rem_parts!(dds, :X, [1,4])
dds = DDS()
add_parts!(dds, :X, 3, Φ=[2,3,3])
s = sprint(show, dds)
-@test occursin("DDS:", s)
-@test occursin("X = 1:3", s)
-@test occursin("Φ : X → X = ", s)
-s = sprint(show, dds, context=:compact => true)
-@test occursin("DDS:", s)
-@test !occursin("\n", s)
-@test occursin("X = 3", s)
+@test contains(s, "DDS:")
+@test contains(s, "X = 1:3")
+@test contains(s, "Φ : X → X = ")
+s = sprint(show, dds, context=:compact=>true)
+@test contains(s, "DDS")
+@test !contains(s, "\n")
+@test contains(s, "X = 3")
s = sprint(show, MIME"text/plain"(), dds)
-@test occursin("DDS", s)
-@test occursin("X = 1:3", s)
-@test occursin("│ X │", s)
+@test contains(s, "DDS")
+@test contains(s, "X = 1:3")
+@test contains(s, "│ X │")
s = sprint(show, MIME"text/html"(), dds)
@test startswith(s, "")
-@test occursin("
", s)
+@test contains(s, "")
@test endswith(rstrip(s), "")
# Special case of pretty print: empty table.
@@ -202,11 +202,11 @@ du = disjoint_union(d, d2)
# Pretty printing of data attributes.
s = sprint(show, d)
-@test occursin("Dendrogram{Int64}:", s)
-@test occursin("height : X → R = ", s)
+@test contains(s, "Dendrogram{Int64}:")
+@test contains(s, "height : X → R = ")
s = sprint(show, MIME"text/plain"(), d)
-@test occursin("Dendrogram{Int64}", s)
+@test contains(s, "Dendrogram{Int64}")
# Allow type inheritance for data attributes.
d_abs = Dendrogram{Number}()
@@ -302,9 +302,9 @@ rem_part!(lset, :X, 1)
# Pretty-printing with unitialized data attribute.
lset = IndexedLabeledSet{Symbol}()
add_part!(lset, :X)
-@test occursin("#undef", sprint(show, lset))
-@test occursin("#undef", sprint(show, MIME"text/plain"(), lset))
-@test occursin("#undef", sprint(show, MIME"text/html"(), lset))
+@test contains(sprint(show, lset), "#undef")
+@test contains(sprint(show, MIME"text/plain"(), lset), "#undef")
+@test contains(sprint(show, MIME"text/html"(), lset), "#undef")
# Labeled sets with unique index
#-------------------------------
diff --git a/test/categorical_algebra/CSets.jl b/test/categorical_algebra/CSets.jl
index d7fb280d4..836137870 100644
--- a/test/categorical_algebra/CSets.jl
+++ b/test/categorical_algebra/CSets.jl
@@ -51,6 +51,7 @@ g, h = path_graph(Graph, 4), cycle_graph(Graph, 2)
@test α[:V] isa FinFunction{Int} && α[:E] isa FinFunction{Int}
@test α[:V](3) == 1
@test α[:E](2) == 2
+@test startswith(sprint(show, α), "ACSetTransformation((V = ")
α′ = CSetTransformation(g, h, V=[1,2,1,2], E=[1,2,1])
@test components(α′) == components(α)
@@ -229,6 +230,7 @@ h = path_graph(WeightedGraph{Float64}, 4, E=(weight=[1.,2.,3.],))
@test α isa LooseACSetTransformation
@test α[:Weight](10.0) == 5.0
@test is_natural(α)
+@test contains(sprint(show, α), "Weight =")
g = star_graph(WeightedGraph{Bool}, 3, E=(weight=[true,false],))
α = ACSetTransformation((V=[2,1,3], E=[2,1], Weight=~), g, g)
diff --git a/test/categorical_algebra/Categories.jl b/test/categorical_algebra/Categories.jl
index 58c84f7b3..5a082532e 100644
--- a/test/categorical_algebra/Categories.jl
+++ b/test/categorical_algebra/Categories.jl
@@ -9,11 +9,14 @@ using Catlab.CategoricalAlgebra.Sets, Catlab.CategoricalAlgebra.Categories
C = TypeCat(FreeCategory.Ob, FreeCategory.Hom)
@test Ob(C) == TypeSet(FreeCategory.Ob)
+@test sprint(show, C) == "TypeCat($(FreeCategory.Ob), $(FreeCategory.Hom))"
-x, y = Ob(FreeCategory, :x, :y)
-f = Hom(:f, x, y)
F = id(C)
@test (dom(F), codom(F)) == (C, C)
+@test startswith(sprint(show, F), "id(TypeCat(")
+
+x, y = Ob(FreeCategory, :x, :y)
+f = Hom(:f, x, y)
@test F(x) == x
@test F(f) == f
diff --git a/test/categorical_algebra/FinCats.jl b/test/categorical_algebra/FinCats.jl
index 933b952ab..0c3ae5282 100644
--- a/test/categorical_algebra/FinCats.jl
+++ b/test/categorical_algebra/FinCats.jl
@@ -18,6 +18,7 @@ C = FinCat(g)
@test hom(C, 1) == Path(g, 1)
@test ob_generators(C) == 1:2
@test hom_generators(C) == 1:3
+@test startswith(sprint(show, C), "FinCat($(Graph)")
h = Graph(4)
add_edges!(h, [1,1,2,3], [2,3,4,4])
@@ -35,6 +36,7 @@ F = FinFunctor((V=[1,4], E=[[1,3], [2,4]]), C, D)
@test codom(F) == D
@test is_functorial(F)
@test Ob(F) == FinFunction([1,4], FinSet(4))
+@test startswith(sprint(show, F), "FinFunctor($([1,4]),")
@test ob_map(F, 2) == 4
@test hom_map(F, 1) == Path(h, [1,3])
@@ -59,6 +61,8 @@ F = FinDomFunctor([FinSet(2), FinSet(3)], [f,g], C)
@test is_functorial(F)
@test dom(F) == C
@test codom(F) isa TypeCat{<:FinSet{Int},<:FinFunction{Int}}
+@test startswith(sprint(show, F), "FinDomFunctor(")
+
@test ob_map(F, 1) == FinSet(2)
@test hom_map(F, 2) == g
@@ -83,6 +87,9 @@ add_edges!(Δ¹_graph, [1,1,2], [2,2,1])
@test graph(Δ¹) == Δ¹_graph
@test length(equations(Δ¹)) == 2
@test !is_free(Δ¹)
+s = sprint(show, Δ¹)
+@test startswith(s, "FinCat($(Graph)")
+@test contains(s, "Path")
# Symbolic categories
#####################
@@ -104,6 +111,7 @@ end
@test first.(hom_generators(Δ¹)) == [:δ₀, :δ₁, :σ₀]
@test length(equations(Δ¹)) == 2
@test !is_free(Δ¹)
+@test startswith(sprint(show, Δ¹), "FinCat(")
# Graph as set-valued functor on a free category.
F = FinDomFunctor(TheoryGraph, path_graph(Graph, 3))
@@ -128,6 +136,8 @@ G = FinDomFunctor(TheoryGraph, g)
@test codom_ob(α) isa TypeCat{<:FinSet{Int},<:FinFunction{Int}}
@test is_natural(α)
@test α[:V](3) == 2
+@test startswith(sprint(show, α), "FinTransformation(")
+
σ = FinTransformation(G, G, V=id(FinSet(2)), E=FinFunction([2,1,4,3]))
@test σ⋅σ == FinTransformation(G, G, V=id(FinSet(2)), E=FinFunction(1:4))
@test α⋅σ == FinTransformation(F, G, V=FinFunction([1,2,2]), E=FinFunction([2,4]))
diff --git a/test/categorical_algebra/FinSets.jl b/test/categorical_algebra/FinSets.jl
index a146b7832..902c4437e 100644
--- a/test/categorical_algebra/FinSets.jl
+++ b/test/categorical_algebra/FinSets.jl
@@ -22,15 +22,14 @@ set = FinSet(Set(1:2:5))
@test startswith(sshow(set), "FinSet(Set(")
# Tables as sets.
-set = FinSet((x=[1,3,5], y=['a','b','c']))
+set = FinSet((x=[1,3,5], y=["a","b","c"]))
@test length(set) == 3
-@test map(NamedTuple, set) == [(x=1, y='a'), (x=3, y='b'), (x=5, y='c')]
+@test map(NamedTuple, set) == [(x=1, y="a"), (x=3, y="b"), (x=5, y="c")]
@test startswith(sshow(set), "TabularSet(")
-@test startswith(sprint(show, MIME("text/plain"), set), "3-element TabularSet")
-
-# Discrete categories
-#####################
+@test startswith(sshow(MIME("text/plain"), set), "3-element TabularSet")
+@test startswith(sshow(MIME("text/html"), set), "