3.3 Hypertees: The Shape of a Hypersnippet of Text
(require punctaffy/hypersnippet/hypertee) | |
package: punctaffy-lib |
3.3.1 Hypertee Coils
syntax
syntax
match expander
procedure
(hypertee-coil-zero? v) → boolean?
v : any/c
Every two hypertee-coil-zero values are equal?.
syntax
syntax
(hypertee-coil-hole overall-degree hole data tails)
match expander
(hypertee-coil-hole overall-degree hole data tails)
procedure
(hypertee-coil-hole? v) → boolean?
v : any/c
procedure
(hypertee-coil-hole-overall-degree coil) → any/c
coil : hypertee-coil-hole?
procedure
(hypertee-coil-hole-hole coil) → any/c
coil : hypertee-coil-hole?
procedure
(hypertee-coil-hole-data coil) → any/c
coil : hypertee-coil-hole?
procedure
(hypertee-coil-hole-tails coil) → any/c
coil : hypertee-coil-hole?
This has four parts: The overall-degree is the degree of the hypertee, the hole is the shape of the hole (carrying trivial? data in its own holes), the data is the data value carried in the hole, and the tails is a hypertee of the same shape as hole, but where the data values are hypertees representing the rest of the structure. The tail hypertee carried in a hole of degree N is expected to have trivial? data in its holes of degree less than N. Its holes of degree not less than N can carry any data; they represent additional holes in the overall hypertee.
Note that the hole is basically redundant here; it’s just the same as tails but with the data values trivialized. Most of our traversal operations make use of values of this form, and some of the places we would construct a typertee already have values of this form readily available, so we save ourselves some redundant computation by keeping it separate. (TODO: Offer an alternative way to create a hypertee-coil-hole without specifying its hole shape.)
On the other hand, we save ourselves some verbosity and some repetitive contract-checking by leaving out the dimension system. If we stored a dimension system alongside the rest of the fields in a hypertee-coil-hole, we could enforce far more precise contracts on the field values, but instead we allow any value to be stored in any of the fields and rely on hypertee-coil/c in the contract of any operation that needs to enforce the structure. (TODO: Reconsider this choice. In most places, we pass a coil to something that associates it with a dimension system as soon as we create it, so we’re effectively passing in the dimension system at the same time anyway. But for the sake of people doing a lot of computation at the coil level, perhaps enforcing contracts is too costly. We’ll probably need more practical experience before we understand the tradeoffs.)
A hypertee based on this kind of coil is essentially created from a snippet-sys-snippet-done in the shape of the hole, concatenated with the tail hypertees using snippet-sys-snippet-join. Considering this, it might be tempting to work with hypertees using only the generic snippet system operations, but even though that interface supplies a way to put together this kind of hypertee, it doesn’t supply a way to take it apart again to work with its details. Pattern-matching on the coils allows the details to be traversed.
Two hypertee-coil-hole values are equal? if they contain equal? elements.
procedure
(hypertee-coil/c ds) → flat-contract?
ds : dim-sys?
Namely: The overall degree (hypertee-coil-hole-overall-degree) must be a nonzero dimension number in the given dimension system. The hole shape must be a hypertee (of any degree) with the given dimension system and with trivial? values in its holes. The tails hypertee must be a hypertee similar to the hole shape, but with hypertees (the tails) in its holes. If a tail appears in a hole of degree N, each of its own holes of degree lower than N must have a trivial? value in it, and those holes must be in the same arrangement as the hole’s holes.
3.3.2 Hypertee Brackets
syntax
syntax
(htb-labeled degree data)
match expander
(htb-labeled degree data)
procedure
(htb-labeled? v) → boolean?
v : any/c
procedure
(htb-labeled-degree b) → any/c
b : htb-labeled?
procedure
(htb-labeled-data b) → any/c
b : htb-labeled?
The given degree is the degree of the hole, and the given data is the data value to be carried in the hole.
The data has to be placed somewhere among the hole’s brackets, and we place it at the first bracket as a stylistic choice for readability: This way, the placement of data values is comparable to the placement of section headings in a document or prefix operators in a Racket program.
Two htb-labeled values are equal? if they contain equal? elements.
syntax
syntax
(htb-unlabeled degree)
match expander
(htb-unlabeled degree)
procedure
(htb-unlabeled? v) → boolean?
v : any/c
procedure
(htb-unlabeled-degree b) → any/c
b : htb-unlabeled?
The given degree is the degree of the hole that’s being initiated by this bracket. Even though this bracket isn’t the first bracket of a hole of the hypertee, it’s still the first bracket of some hole. It could be the first bracket of a hole of a hole of the hypertee; the first bracket of a hole of a hole of a hole of the hypertee; etc.
Two htb-unlabeled values are equal? if they contain equal? elements.
procedure
(hypertee-bracket? v) → boolean?
v : any/c
procedure
(hypertee-bracket/c dim/c) → contract?
dim/c : contract?
The resulting contract has the same contract obstinacy as the given one.
3.3.3 Hypertee Constructors and Operations
procedure
(hypertee-get-dim-sys ht) → dim-sys?
ht : hypertee?
syntax
syntax
(hypertee-furl ds coil)
ds : dim-sys?
coil : (hypertee-coil/c ds)
match expander
(hypertee-furl ds coil)
Two hypertees are equal? if they contain equal? elements when seen this way. Note that this isn’t the only way to understand their representation; they can also be seen as being constructed by hypertee-from-brackets.
procedure
(hypertee-get-coil ht)
→ (hypertee-coil/c (hypertee-get-dim-sys ht)) ht : hypertee?
procedure
(hypertee-from-brackets ds degree brackets) → (hypertee/c ds)
ds : dim-sys? degree : (dim-sys-dim/c ds) brackets : (listof (hypertee-bracket/c (dim-sys-dim/c ds)))
If the brackets aren’t properly nested, the exn:fail:contract exception is raised.
Proper nesting of hypertee brackets is a rather intricate matter which is probably easiest to approach by thinking of it as a series of hyperstack pop operations. The hyperstack starts out with a dimension of degree and data of #t at every dimension, and each bracket in the list performs a hyperstack-pop with data of #f. (A hyperstack-pop in some sense simultaneously "pushes" that data value onto every lower dimension. See the hyperstack documentation for more information.) If the pop reveals the data #t, the bracket should have been htb-labeled?; otherwise, it should have been htb-unlabeled?. Once we reach the end of the list, the hyperstack should have a dimension of 0 (in the sense of dim-sys-dim-zero).
Two hypertees are equal? if they’re constructed with equal? elements this way. Note that this isn’t the only way to understand their representation; they can also be seen as being constructed by hypertee-furl.
(TODO: Write some examples.)
procedure
(ht-bracs ds degree bracket ...) → (hypertee/c ds)
ds : dim-sys? degree : (dim-sys-dim/c ds)
bracket :
(let ([dim/c (dim-sys-dim/c ds)]) (or/c (hypertee-bracket/c dim/c) (and/c (not/c hypertee-bracket?) dim/c)))
If the brackets aren’t properly nested, the exn:fail:contract exception is raised.
Rarely, some dimension system might represent its dimension numbers as hypertee-bracket? values. If that’s the case, then those values must be explicitly wrapped in htb-unlabeled. Otherwise, this will understand them as brackets instead of as dimension numbers.
This is simply a more concise alternative to hypertee-from-brackets. See that documentation for more information about what it takes for hypertee brackets to be "properly nested."
(TODO: Write some examples.)
procedure
→ (listof (hypertee-bracket/c (dim-sys-dim/c ds))) ht : hypertee?
procedure
(hypertee/c ds) → flat-contract?
ds : dim-sys?
syntax
syntax
(hypertee-snippet-sys dim-sys)
dim-sys : dim-sys?
match expander
(hypertee-snippet-sys dim-sys)
procedure
v : any/c
procedure
ss : hypertee-snippet-sys?
The resulting snippet system’s operations have behavior which corresponds to the sense in which we’ve described hypertees as being higher-dimensional snippets snipped out of content-free streams. Consider the snippet-sys-snippet-splice and snippet-sys-snippet-zip-map-selective operations, which iterate over all the holes of a hypersnippet. In the case of a hypertee, they iterate over each of the hypertee-coil-hole/htb-labeled nodes exactly once (notwithstanding early exits and the skipping of unselected? data values), so indeed each of these nodes legitimately represents one of the hypertee’s holes. We’ve chosen to directly describe operations like hypertee-coil-hole in terms of hypersnippet holes, largely because the very purpose of hypertees is tied to the functionality they have as hypersnippets. Because of this, "hypertee-coil-hole nodes really do correspond to holes" may sound tautological, but in fact the behavior of this snippet system is the reason we’ve been able to describe those nodes in terms of holes in the first place.
(TODO: This isn’t really a complete specification of the behavior. A complete specification might get very exhaustive or technical, but let’s see if we can at least improve this description over time. Perhaps we should go through and hedge some of the ways we describe hypertees so that they specifically appeal to hypertee-snippet-sys as the basis for their use of terms like "hypersnippet," "degree," and "hole.")
Two hypertee-snippet-sys values are equal? if they contain equal? elements. One such value is an ok/c match for another if the first’s element is ok/c for the second’s.
syntax
syntax
match expander
procedure
v : any/c
The shapes and snippets are related according to the same behavior as hypertee-snippet-sys. In some sense, this is a generalization of hypertee-snippet-sys which puts the choice of dimension system in the user’s hands. Instead of merely generalizing by being more late-bound, this also generalizes by having slightly more functionality: The combination of functor-from-dim-sys-sys-apply-to-morphism with snippet-format-sys-functor allows for transforming just the degrees of a hypertee while leaving the rest of the structure alone.
Every two hypertee-snippet-format-sys values are equal?. One such value is always an ok/c match for another.
procedure
ht : (and/c hypertee? (hypertee/c (hypertee-get-dim-sys ht)))
(TODO: Not all snippet systems necessarily support an operation like this, but all the ones we’ve defined so far do. It may turn out that we’ll want to add this to the snippet system interface.)