Next: , Previous: , Up: Top   [Contents][Index]

2 Fundamental Types

Central to change ringing is permuting sequences of a fixed collection of bells, where the cardinality of that collection is the stage. For modeling such things Roan provides the types bell, stage and row, and various operations on them. It is also provides tools for reading and writing place notation.


Next: , Up: Fundamental Types   [Contents][Index]

2.1 Bells

Roan supports ringing on as few as 2, or as many as 24, bells. Bells are represented as small, non-negative integers less than this maximum stage. However, bells as the integers used in Roan are zero-based: the treble is zero, the tenor on eight is 7, and so on. The bell type corresponds to integers in this range. There are functions for mapping bells to and from the characters corresponding to their usual textual representation in change ringing.

Type: bell

A representation of a bell. These are zero-based, small integers, so the treble is 0, the second is 1, up to the tenor is one less than the stage.

Function: bell-name bell &optional upper-case

Returns a character denoting this bell, or nil if bell is not a bell. If the character is alphabetic, an upper case letter is returned if the generalized boolean upper-case is true, and otherwise a lower case letter. If upper-case is not supplied it defaults to the current value of *print-bells-upper-case*.

 (bell-name 0) ⇒ #\1
 (map 'string #'bell-name
      (loop for i from 0 below +maximum-stage+
            collect i))
     ⇒ "1234567890ETABCDFGHJKLMN"
 (bell-name -1) ⇒ nil
 (bell-name +maximum-stage+) ⇒ nil
Function: bell-from-name char

Returns the bell denoted by the character designator char, or nil if it is not a character designator denoting a bell. The determination is case-insensitive.

 (bell-from-name "8") ⇒ 7
 (bell-from-name "E") ⇒ 10
 (map 'list #'bell-from-name "135246") ⇒ (0 2 4 1 3 5)
 (bell-from-name "%") ⇒ nil
Variable: *print-bells-upper-case*

When printing bell names that are letters, whether or not to use upper case letters by default. It is a generalized boolean, with an initial default value of t.


Next: , Previous: , Up: Fundamental Types   [Contents][Index]

2.2 Stages

The stage type represents the subset of small, positive integers corresponding to the numbers of bells Roan supports. While Roan represents stages as small, positive integers, it is conventional in ringing to refer to them by names, such as “Minor” or “Caters”. There are functions for mapping stages, the integers used by Roan, to and from their conventional names as strings.

Type: stage

A supported number of bells, an integer between +minimum-stage+ and +maximum-stage+, inclusive.

Constant: +minimum-stage+

The smallest number of bells supported, 2.

Constant: +maximum-stage+

The largest number of bells supported, 24.

Function: stage-name stage

Returns a string, the conventional name for this stage, capitalized, or nil if stage is not an integer corresponding to a supported stage.

 (stage-name 8) ⇒ "Major"
 (stage-name 22) ⇒ "Twenty-two"
 (stage-name (1+ +maximum-stage+)) ⇒ nil
Function: stage-from-name name

Returns a stage, a small, positive integer, with its name the same as the string designator name, or, if there is no stage with such a name, nil. The determination is made case-insensitively.

 (stage-from-name "cinques") ⇒ 11
 (stage-from-name "no-such-stage") ⇒ nil
Variable: *default-stage*

An integer, the default value for optional or keyword arguments to many functions that must have a stage specified. See write-row, row-string, write-place-notation and place-notation-string.


Next: , Previous: , Up: Fundamental Types   [Contents][Index]

2.3 Rows

The fundamental units of change ringing are rows and changes, permutations of a fixed set of bells. A distinction between them is often made, where a row is a permutation of bells and a change is a permutation taking one row to the next. In Roan they are both represented by the same data type, row; rows should be treated as immutable.

The Lisp reader can be augmented by Roan to read rows printed in the notation usually used by change ringers by using the ‘!’ reader macro. For example, queens on twelve can be entered in Lisp as !13579E24680T. When read with the ‘!’ reader macro bells represented by alphabetic characters can be either upper or lower case; so queens on twelve can also be entered as !13579e24680t or !13579e24680T.

To support the common case of writing lead heads of treble dominated methods if the treble is leading it can be omitted. Thus, queens on twelve can also be entered as !3579E24680T. Apart from a leading treble, however, if any bell is omitted from a row written with a leading ‘!’ character an error will be signaled.

Note that rows are Lisp atoms, and thus literal values can be written using ‘!’ notation without quoting, though quoting rows read that way will do no harm when they are evaluated.

This ‘!’ syntax can be turned on and off by using roan-syntax. By default it is off when Roan is loaded. It is also possible to control this syntax by using Named Readtables; see roan-syntax for further details.

Similarly, rows are printed using this same notation, *print-escape* controlling whether or not they are preceded by ‘!’ characters. Note that the characters used to represent bells in this printed representation differ from the small integer bells used to represent them internally, since the latter are zero based. For example, the treble is represented internally by the integer 0, but in this printed representation by the digit character ‘1’. When printing rows in this way a leading treble is not elided. And *print-bells-upper-case* can be used to control the case of bells in the printed representation of rows that are representated by letters, in cinques and above.

CL-USER> !12753468
!12753468
CL-USER> '!2753468
!12753468
CL-USER> (format t "with:    ~S~%without:  ~:*~A~%" !TE0987654123)
with:    !TE0987654123
without:  TE0987654123
NIL
CL-USER> (let ((roan:*print-bells-upper-case* nil))
           (format nil "~A" !TE0987654123))
"te0987654123"
CL-USER>

Rows can be compared for equality using equalp (but not equal). That is, two different row objects that correspond to the same ordering of the same number of bells will be equalp. Hash tables with a :test of equalp are often useful with rows. See hash-set.

 (equalp !13572468 !13572468) ⇒ t
 (equalp !13572468 !12753468) ⇒ nil
 (equalp !13572468 !1357246) ⇒ nil
 (equalp !13572468 !3572468) ⇒ t
Type: row

A permutation of bells at a particular stage. The type row is used to represent both change ringing rows and changes; that is, rows may be permuted by other rows. Instances of row should normally be treated as immutable.

Macro: roan-syntax &optional on-off modify

Turns on or off the read macros for ‘!’ and ‘#!’, for reading rows and place notation.

If the generalized boolean on-off is true, the default, it turns on these read macros. Unless the generalized boolean modify is false, the default, it first pushes the current read table onto a stack, modifying a copy of it and making that copy the current read table. If modify is true it makes no copy and instead modifies the current readtable in place.

If on-off is false it restores the previous readtable by popping the stack. If the stack is empty it sets the readtable to a new, standard one. When on-off is false modify is ignored.

This is performed in an eval-when context to ensure it happens at compile time as well as load and execute time.

An alternative to using roan-syntax is to use Named Readtables. Roan defines two such readtables with names :roan and :roan+interpol. The former augments the initial Common Lisp read table with Roan’s read macros, and the latter also adds the syntax from CL-INTERPOL.

Function: row-p object

Non-nil if and only if object is a row.

Function: stage row

The number of bells of which the row row is a permutation.

Function: write-row row &key stream escape upper-case

Writes row, which should be a row, to the indicated stream. The case of any bells represented by letters is controlled by upper-case, a generalized boolean defaulting to the current value of *print-bells-upper-case*. escape, a generalized Boolean defaulting to the current value of *print-escape*, determines whether or not to write it in a form that read can understand. Signals a type-error if row is not a row, and the usual errors if stream is not open for writing, etc.

Function: row-string row &optional upper-case

Returns a string representing the row row. The case of any bells represented by letters is controlled by upper-case, a generalized boolean defaulting to the current value of *print-bells-upper-case*. Signals a type-error if row is not a row.

Function: read-row &optional stream eof-error-p eof-value recursive-p

Constructs and returns a row from the conventional symbols for bells read from the stream. The stage of the row read is determined by the bells present, that is by the largest bell for which a symbol is read. The treble can be elided, in which case it is assumed to be leading; a parse-error is signaled if any other bell is omitted. Bells represented by letters can be either upper or lower case.

Function: parse-row string &key start end junk-allowed

Contructs a row from the conventional symbols for bells in the section of string string delimited by start and end, possibly preceded or followed by whitespace. The treble can be elided, in which case it is assumed to be leading; a parse-error is signaled if any other bell is omitted. Bells represented by letters can be either upper or lower case. If string is not a string a type-error is signaled. If the generalized boolean junk-allowed is false, the default, an error will be signaled if additional non-whitespace characters follow the representation of a row. Returns two values: the row read and a non-negative integer, the index into the string of the next character following all those that were parsed, including any trailing whitespace; if parsing consumed the whole of string, the second value will be length of string.

Function: row &rest bells

Constructs and returns a row containing the bells, in the order they appear in the argument list. If the treble is not present, it defaults to being the first bell in the row. Duplicate bells or bells other than the treble missing result in an error being signaled.

 (row 2 1 3 4 7 6 5) ⇒ !13245876
Function: rounds &optional stage

Returns a row representing rounds at the given stage, which defaults to *default-stage* Signals a type-error if stage is not a stage, that is an integer between +minimum-stage+ and +maximum-stage+, inclusive.

Function: bell-at-position row position
Function: position-of-bell bell row

The bell-at-position function returns the bell (that is, a small integer) at the given position in the row. The position-of-bell function returns position of bell in row, or nil if bell does not appear in row. The indexing into row is zero-based; so, for example, the leading bell is at position 0, not 1. Signals an error if row is not a row, or if position is not a non-negative integer or is too large for the stage of row

 (bell-at-position !13572468 3) ⇒ 6
 (bell-name (bell-at-position !13572468 3)
     ⇒ #\7
 (position-of-bell 6 !13572468) ⇒ 3
 (position-of-bell (bell-from-name #7) !13572468)
     ⇒ 3
Function: bells-list row
Function: bells-vector row &optional vector

The bells-list function returns a fresh list of bells (small, non-negative integers, zero-based), the bells of row, in the same order that they appear in row. The bells-vector function returns a vector of bells (small, non-negative integers, zero-based), the bells of row, in the same order that they appear in row. If vector is not supplied or is nil a freshly created, simple general vector is returned.

 (bells-list !13572468) ⇒ (0 2 4 6 1 3 5 7)
 (bells-vector !142536) ⇒ #(0 3 1 4 2 5)

If a non-nil vector is supplied the bells are copied into it and it is returned. If vector is longer than the stage of row only the first elements of vector, as many as the stage of row, are over-written; the rest are unchanged. If vector is shorter than the stage of row, then, if it is adjustable, it is adjusted to be exactly as long as the stage of row, and otherwise an error is signaled without any modifications made to the contents of vector or its fill-pointer, if any. If vector has a fill-pointer and is long enough to hold all the bells of row, possibly after adjustment, its fill-pointer is set to the stage of row.

A type-error is signaled if row is not a row. An error is signled if vector is neither nil nor a vector with an element type that is a supertype of bell, and of sufficient length or adjustable.

Function: reversed-row row

Returns a row of the same stage as row with its bells in the reverse order. A type-error is signaled if row is not a row.

 (reversed-row !32148765) ⇒ !56784123

Next: , Up: Rows   [Contents][Index]

2.3.1 Properties of rows

Function: roundsp row

True if and only if row is a row representing rounds at its stage.

 (roundsp !23456) ⇒ t
 (roundsp !123546) ⇒ nil
 (roundsp 123456) ⇒ nil
Function: changep row

True if and only if row is a row representing a permutation with no bell moving more than one place.

 (changep !214365) ⇒ t
 (changep !143265) ⇒ nil
 (changep |214365|) ⇒ nil
Function: placesp row &rest places

Returns true if and only if row is a (non-jump) change, with exactly the specified places being made, and no others. To match a cross at even stages supply no places.

Signals a type-error if row is not a row or any of places are not bells. Signals an error if any of places are not less than the stage of row, or are duplicated.

 (placesp !21354768 2 7) ⇒ t
 (placesp !21346587 2 7) ⇒ nil
 (placesp !21354768 2) ⇒ nil
 (placesp !2135476 2) ⇒ t
 (placesp !21436587) ⇒ t
Function: in-course-p row

True if and only if row is a row representing an even permutation.

 (in-course-p !132546) ⇒ t
 (in-course-p !214365) ⇒ nil
 (in-course-p "132546") ⇒ nil
Function: involutionp row

True if and only if row is a row that is its own inverse.

 (involutionp !13248765) ⇒ t
 (involutionp !13425678) ⇒ nil
 (involutionp nil) ⇒ nil
Function: order row

Returns a positive integer, the order of row: the minimum number of times it must be permuted by itself to produce rounds. A type-error is signaled if row is not a row.

 (order !13527486) ⇒ 7
 (order !31256784) ⇒ 15
 (order !12345678) ⇒ 1
Function: cycles row

Returns a list of lists of bells. Each of the sublists is the orbit of all of its elements in row. One cycles are included. Thus, if row is a lead head, all the sublists of length one are hunt bells, all the rest being working bells; if there are two or more sublists of length greater than one the corresponding method is differential. The resulting sublists are each ordered such that the first bell is the lowest numbered bell in that cycle, and the remaining bells occur in the order in which a bell traverses the cycle. Within the top level list, the sublists are ordered such that the first bell of each sublist appear in ascending numerical order.

 (cycles !13572468) ⇒ ((0) (1 4 2) (3 5 6) (7))
 (format nil "~{(~{~C~^,~})~^, ~}"
             (mapcar #'(lambda (x) (mapcar #'bell-name x))
             (cycles !13572468)))
     ⇒ "(1), (2,5,3), (4,6,7), (8)"
Function: tenors-fixed-p row &optional starting-at

Returns true if and only if all the bells of row at positions starting-at or higher are in their rounds positions. In the degenerate case of starting-at being equal to or greater than the stage of row it returns true. Note that it is equivalent to (not (null (alter-stage row starting-at))). If not supplied starting-at defaults to 6, that is the position of the bell conventionally called the seven, though represented in Roan by the small integer 6. Signals a type-error if row is not a row or starting-at is not a non-negative integer.

 (tenors-fixed-p !13254678) ⇒ t
 (tenors-fixed-p !13254678 5) ⇒ t
 (tenors-fixed-p !13254678 4) ⇒ nil
 (tenors-fixed-p !54321) ⇒ t
 (tenors-fixed-p !54321 4) ⇒ nil
Function: which-plain-bob-lead-head row

If row is a lead head of a plain course of Plain Bob at its stage returns a positive integer identifying which lead head it is; returns nil if row is not a Plain Bob lead head. If row is the first lead head of a plain course of Plain Bob 1 is returned, if the second 2, etc. For the purposes of this function rounds is not a Plain Bob lead head, nor is any row below minimus. Signals a type-error if row is not a row.

 (which-plain-bob-lead-head !13527486) ⇒ 1
 (which-plain-bob-lead-head !42638507T9E) ⇒ 10
 (which-plain-bob-lead-head !129785634) ⇒ nil
 (which-plain-bob-lead-head !12345) ⇒ nil
 (which-plain-bob-lead-head !132) ⇒ nil
Function: which-grandsire-lead-head row

If row is a lead head of a plain course of Grandsire at its stage returns a positive integer identifying which lead head it is; returns nil if row is not a Grandsire lead head. If row is the first lead head of a plain course of Grandsire 1 is returned, if the second 2, etc. For the purposes of this function rounds is not a Grandsire lead head, nor is any row below minimus. Signals a type-error if row is not a row.

 (which-plain-bob-lead-head !1253746) ⇒ 1
 (which-plain-bob-lead-head !28967453) ⇒ 4
 (which-plain-bob-lead-head !135264) ⇒ nil
 (which-plain-bob-lead-head !1243) ⇒ 1
 (which-plain-bob-lead-head !12345) ⇒ nil

Previous: , Up: Rows   [Contents][Index]

2.3.2 Permuting rows

Function: permute row &rest changes

Permutes row by the changes in turn. That is, row is first permuted by the first of the changes, then the resuling row is permuted by second of the changes, and so on. Returns the row resulting from applying all the changes. So long as one or more changes are supplied the returned row is always a freshly created one: row and none of the changes are modified (as you’d expect, since they are intended to be viewed as immutable). The row and all the changes should be rows.

At each step of permuting a row by a change, if the row is of higher stage than the change, only the first stage bells of the row are permuted, where stage is the stage of the change, all the remaining bells of the row being unmoved. If the row is of lower stage than the change, it is as if the row were extended with bells in their rounds’ positions for all the bells stage and above. Thus the result of each permuation step is a row whose stage is the larger of those of the row and the change.

If no changes are supplied row is returned. Signals a type-error if row or any of the changes are not rows.

 (permute !34256 !35264) ⇒ !145362
 (permute !34125 !4321 !1342) ⇒ !24315
 (permute !4321 !654321) ⇒ !651234
 (let ((r !13572468))
   (list (eq (permute r) r)
         (equalp (permute r (rounds 8)) r)
         (eq (permute r (rounds 8)) r)))
     ⇒ (t t nil)
Function: permute-collection collection change
Function: permute-by-collection row collection
Function: npermute-collection collection change
Function: npermute-by-collection row collection

Permutes each of the elements of a sequence or hash-set and an individual row, collecting the results into a similar collection. The permute-collection version permutes each the elements of collection by change; permute-by-collection permutes row by each of the elements of collection by change. The return value is a list, vector or hash-set if collection is a list, vector or hash-set, respectively. The permute-collection and permute-by-collection versions always return a fresh collection; the npermute-collection and npermute-by-collection versions modify collection, replacing its contents by the permuted rows. If collection is a sequence the contents of the result are in the same order: that is, the Nth element of the result is the Nth element supplied in collection permuted by or permuting change or row. If collection is a vector, permute-collection and permute-by-collection always return a simple, general vector.

If the result is a sequence, or if all the elements of collection were of the same stage as one another, it is guaranteed that the result will be the same length or cardinality as collection. However, if collection is a hash-set containing rows of different stages the result may be of lower cardinality than then the supplied hash-set, if collection contained two or more elements that were not equalp because they were of different stages, but after being permuted by, or permuting, a higher stage row the results are equalp.

Signals a type-error if change, row or any of the elements of collection are not rowss, or if collection is not a sequence or hash-set.

Function: generate-rows changes &optional initial-row
Function: ngenerate-rows changes &optional initial-row

Generates a sequence of rows by permuting a starting row successively by each element of the sequence changes. The elements of changes should be rows. If initial-row is supplied it should be a row. If it is not supplied, rounds at the same stage as the first element of changes is used; if changes is empty, rounds at *default-stage* is used. Two values are returned. The first is a sequence of the same length as changes, and the second is a row. So long as changes is not empty, the first element of the first return value is initial-row, or the default rounds. The next value is that row permuted by the first element of changes; then that row permuted by the next element of changes, and so on, until all but the last element of changes has been used. The second return value is the last element of the first return value permuted by the last element of changes. If changes is empty, then the first return value is also empty, and initial-row, or the default rounds, is the second return value. Thus, for most methods, if changes are the changes of a lead, the first return value will be the rows of a lead starting with initial-row, and the second return value the lead head of the following lead.

If changes is a list, the first return value is a list; if changes is a vector, the first return value is a vector. The generate-rows function always returns a fresh sequence as its first return value, while ngenerate-rows resuses changes, replacing its elements by the permuted rows and returning it. The fresh vector created and returned by generate-rows is always a simple, general vector.

Signals an error if initial-row is neither a row nor nil, if changes isn’t a sequence, or if any elements of changes are not rows.

 (multiple-value-list
   (generate-rows '(!2143 !1324 !2143 !1324) !4321))
     ⇒ ((!4321 !3412 !3142 !1324) !1234)
Function: permutation-closure &rest rows

Returns a list of distinct rows that can be generated by permuting, repeatedly if necessary, any of the rows by themselves or any others of the rows. If the rows are not all of the same stage, the lower stage ones are converted to the highest stage present before the closure operation is performed. The order of the returned rows is undefined. Signals a type-error if any of the rows is not a row.

 (permutation-closure !13425 !1324 !123465)
   ⇒ (!143265 !142365 !124365 !142356 !143256 !124356
       !134265 !132465 !123456 !123465 !132456 !134256)
Function: inverse row

Returns the inverse of the row row. That is, the row, r, such that when row is permuted by r, the result is rounds. A theorem of group theory implies also that when r is permuted by row the result will also be rounds. Signals a type-error if row is not a row.

 (inverse !13427586) ⇒ !14236857
 (inverse !14236857) ⇒ !13427586
 (inverse !12436587) ⇒ !12436587
 (inverse !12345678) ⇒ !12345678
Function: permute-by-inverse row change

Equivalent to (permute row (inverse change)). Signals a type-error if either row or change is not a row.

 (permute-by-inverse !13456287 !45678123) ⇒ !28713456
 (permute-by-inverse !54312 !2438756) ⇒ !54137862
 (permute-by-inverse !762345 !4312) ⇒ !6271345
Function: alter-stage row &optional new-stage

If there is a row, r, of stage new-stage such that (equalp (permute (rounds new-stage) r) row) then returns r, and otherwise nil. That is, it returns a row of the new-stage such that the first bells are as in row, and any new or omitted bells are in rounds order. If not supplied new-stage defaults to the current value of *default-stage*. Signals a type-err if row is not a row or new-stage is not a stage.

 (alter-stage !54321 10) ⇒ !5432167890
 (alter-stage !5432167890 6) ⇒ !543216
 (alter-stage !54321 4) ⇒ nil
 (alter-stage !5432167890 4) ⇒ nil

Previous: , Up: Fundamental Types   [Contents][Index]

2.4 Place notation

Place notation is a succinct notation for writing sequences of changes, and is widely used in change ringing. Roan provides functions for reading and writing place notation, producing lists of rows, representing changes.

Place notation manipulated by Roan is extended to support jump changes and comma as an unfolding operator for easy notation of palindromic sequences of changes.

Jump changes may be included in the place notation in two ways. Within changes may appear parenthesized pairs of places, indicating that the bell in the first place jumps to the second place. Thus the change (13)6 corresponds to the jump change 231546. As usual implied leading or lying places may be omitted, so that could also be written simply (13). However, just as with ordinary place notation, all internal places must be noted explicitly; for example, the change (13)(31) is illegal, and must be written (13)2(31). Using this notation the first half-lead of London Treble Jump Minor can be written 3x3.(24)x2x(35).4x4.3.

Jump changes may also be written by writing the full row between square brackets. So that same half-lead of London Treble Jump Minor could instead be notated 3x3[134265]x2x[214536]4x4.3. Or they can be mixed 3x3[134265]x2x(35).4x4.3.

Palindromes may be conveniently notated using a comma operator, which means the changes preceding the comma are rung backwads, following the last of the changes before the comma, which is not repeated; followed by the changes following the comma, similarly unfolded. Thus x3x4,2x3 is equivalent to x3x4x3x2x3x2. A piece of place notation may include at most one comma. Neither the changes before the comma nor after it may be empty. Any piece of place notation including a comma is necessarily of even length.

If jump changes appear in place notation that is being unfolded then when rung in reverse the jump changes are inverted; this makes no difference to ordinary changes, which are always involutions, but is important for jump changes that are not involutions. If the central change about which the unfolding operation takes place, that is the last change in a sequence of changes being unfolded, is not an involution an error is signaled. As an example, a plain lead of London Treble Jump Minor can be notated as 3x3.(24)x2x(35).4x4.3,2 which is equivalent to 3x3.(24)x2x(35).4x4.3.4x4.(53)x2x(42).3x3.2.

While place notation is normally written using dots (full stops) only between non-cross changes, parse-place-notation will accept, and ignore, them between any changes, adjacent to other dots, and before and after place notation to be parsed. This may simplify operation with other software that emits place notation with extraneous dots.

Just as Roan can augment the Lisp reader with ‘!’ to read rows, it can augment it with the ‘#!’ reader macro to read place notatation. The stage at which the place notation is to be interpreted can be written as an integer between the ‘#’ and the ‘!’. If no explict stage is provided the current value (at read time) of *default-stage* is used. The sequence of place notation must be followed by a character that cannot appear in place notation, such as whitespace, or by end of file. There is an exception that an unbalanced close parenthesis will also end the reading; this allows using this to read place notation in lists and vectors without requiring whitespace following the place notation. The place notation may be extended with the comma unfolding operator, and with jump changes. The stage at which the place notation is being iterpreted is not considered in deciding which characters to consume; all that might apply as place notation at any stage will be consumed. If some are not appropriate an error will only be signaled after all the continguous, place notation characters have been read.

Note that, unlike rows, which are Lisp atoms, the result of reading place notation is a list, so ‘#!’ quotes it. This is appropriate in the usual case where the result of ‘#!’ is evaluated, but if used in a context where it is not evaluated care must be exercised.

This ‘#!’ syntax can be turned on and off by using roan-syntax. By default it is off when Roan is loaded. It is also possible to control this syntax by using Named Readtables; see roan-syntax for further details.

 ROAN> #6!x2,1
 (!214365 !124365 !214365 !132546)
 ROAN> '(symbol #6!x2,1 x #6!x2x1)
 (SYMBOL '(!214365 !124365 !214365 !132546) X
         '(!214365 !124365 !214365 !132546))
 ROAN> `(symbol ,#6!x2,1 x ,#6!x2x1)
 (SYMBOL (!214365 !124365 !214365 !132546) X
         (!214365 !124365 !214365 !132546))
 ROAN> #6!x2
 (!214365 !124365)
 ROAN> (equalp #10!x1x4,2 #10!x1x4x1x2)
 T
 ROAN> #6!x3.(13)(64)
 (!214365 !213546 !231645)
 ROAN> #6!x3.(13).(64)
 (!214365 !213546 !231546 !132645)
 ROAN> #6!x3[231546](64)
 (!214365 !213546 !231546 !132645)
Function: parse-place-notation string &key stage start end junk-allowed

Parses place notation from string, returning a list of rows, representing changes, of stage stage. The place notation is parsed as applying to stage stage, which, if not supplied, defaults to current value of *default-stage*. Only that portion of string between start and end is parsed; start should be a non-negative integer, and end either an integer larger than start or nil, which latter is equivalent to the length of string. If junk-allowed, a generalized Boolean, is nil, the default, string must consist of the place notation parsed and nothing else; otherwise non-place notation characters may follow the place notation. For purposes of parsing stage is not initially considered: if the place notation is only appropriate for higher stages it will not terminate the parse even if junk-allowed is true, it will instead signal an error. Two values are returned. The first is a list of rows, the changes parsed. The second is the index of the next character in string following the place notation that was parsed.

If the section of string delimited by start and end does not contain place notation suitable for stage a parse-error is signaled. If string is not a string, stage is not a stage or start or end are not suitable bounding index designators a type-error is signaled.

 (multiple-value-list (parse-place-notation "x2.3" :stage 6))
     ⇒ ((!214365 !124365 !213546) 4)
Function: read-place-notation &optional stream stage eof-error-p eof-value recursive-p

Reads place notation from a stream, resulting in a list of rows representing changes. Reads all the consecutive characters that can appear in (extended) place notation, and then tries to parse them as place notation. It accumulates characters that could appear as place notation at any stage, even stages above stage. The sequence of place notation must be followed by a character that cannot appear in place notation, such as whitespace, or by end of file. There is an exception, in that an unbalanced close parenthesis will also end the read; this allows using this to read place notation in lists and vectors without requiring whitespace following the place notation. The place notation may be extended with the comma unfolding operator, and with jump changes, as in parse-place-notation. The argument stream is a character stream open for reading, and defaults to the current value of *standard-input*; stage is a stage, an integer, and defaults to the current value of *default-stage*; and eof-error-p, eof-value and recursive-p are as for the standard read function, defaulting to t, nil and nil, respectively. Returns a non-empty list of rows, all of stage stage. Signals an error if no place notation constituents are available, if the characters read cannot be parsed as (extended) place noation at stage, or if one of the usual errorneous conditions while reading occurs.

Function: write-place-notation changes &key stream escape comma elide cross upper-case jump-changes

Writes to stream characters representing place notation for changes, a list of rows.

The list changes should be a non-empty list of rows, all of the same stage. The stream should a character stream open for writing. It defaults to the current value of *standard-output*. If the generalized boolean escape, which defaults to the current value of *print-escape*, is true the place notation will be written using the ‘#!’ read macro to allow the Lisp read function to read it; in this case the stage will always be explicitly noted between the ‘#’ and the ‘!’. If the generalized boolean upper-case, which defaults to the current value of *print-bells-upper-case*, is true positions notated using letters will be written in upper case, and otherwise in lower case.

The argument cross controls which character is used to denote a cross change at even stages. It must be a character designator for #\x, #\X or #\-, and defaults to the current value of *cross-character*.

The argument jump-changes should be one of nil, :jumps or :full. It determines how jump changes will be notated. If it is nil and changes contains any jump changes an error will be signaled. If it is :jumps any jump changes will be notated using pairs of places between parentheses. While parse-place-notation and read-place-notation can interpret ordinary conjunct motion or even place making notated in parentheses, write-place-notation will only use parentheses for bells actually moving more than one place. If jump-changes is :full jump changes will be notated as a row between square brackets. Again, while ordinary changes notated this way can be parsed or read, write-place-notation will only use bracket notation for jump changes.

The argument elide determines whether, and how, to omit leading and/or lying places. If the stage of the changes in changes is odd, or if elide is nil, no such elision takes place. Otherwise elide should be one of :interior, :leading, :lying or :lead-end, which last is its default value. For any of these non-nil values leading or lying places will always be elided if there are interior places. They differ only for hunts (that is, changes with both a leading and lying place, and no interior places). If :interior, no elision takes place if there are no interior places. If :leading, the ’1’ is elided as implicitly available. If :lying, the lying place is elided, so that the result is always ’1’. The value :lead-end specifies the same behavior as :lying for all the elements of changes except the last, for which it behaves as :leading; this is often convenient for notating leads of treble dominated methods at even stages.

If the generalized boolean comma is true an attempt is made to write changes using a comma operator separating it into palindromes. In general there can be multiple ways of splitting an arbitrary piece of place notation into palindromes. If this is the case the choice is made to favor first a division that has the palindrome after the comma of length one, and if that is not possible the division that has the shortest palindrome before the comma. Any sequence of changes of length two can be trivially divided into palindromes, but notating them with a comma is unhelpful, so comma applies only to even length lists of changes of length greater than two. Whether or not a partitioning into palindromes was possible can be determined by examining the second value returned by this function, which will be true only if a comma was written.

Returns two values, changes, and a generalized Boolean indicating whether or not the result was written with a comma.

Signals an error if changes is empty, or contains rows of different stages, if stream is not a character stream open for writing, or if any of the usual IO errors occurs.

Function: place-notation-string changes &key comma elide cross upper-case allow-jump-changes

Returns a string of the place notation representing the list changes. The arguments are the same as the like named arguments to write-place-notation. A leading ’#!’ is never included in the result.

Signals a type-error if any elements of changes are not rows. Signals an error if changes is empty or contains rows of different stages.

 (multiple-value-list
   (place-notation-string #8!x1x4,1 :elide nil))
     ⇒ ("x18x14x18x18" nil)
 (multiple-value-list
   (place-notation-string #8!x1x4,1 :comma t))
     ⇒ ("x1x4,8" t)
 (multiple-value-list
   (place-notation-string #8!x1x4,2 :elide :interior))
     ⇒ ("x18x4x18x18" nil)
Function: canonicalize-place-notation string-or-changes &key stage comma elide cross upper-case allow-jump-changes

Returns a string representing the place notation in a canonical form. If string-or-changes is a string it should be parseable as place notation at stage, which defaults to the current value of *default-stage*, and otherwise it should be a list of rows, all of the same stage. Unless overridden by the other keyword arguments, which have the same effects as for write-place-notation, the canonical form is a compact one using lower case ‘x’ for cross, upper case letters for high place names, lead-end style elision of external places, a comma for unfolding if possible, and notating jump changes as jumps within parentheses.

Signals a type-error if string-or-changes is neither a string nor a list, or if it is a list containing anything other than rows. Signals a parse-error if string-or-changes is a string and is not parseable at stage, or if stage is not a stage. Signals an error if cross is not a suitable character designator, if allow-jump-changes is not one of its allowed values, or if string-or-changes is a list containing rows of different stages. See write-place-notation.

 (multiple-value-list
   (canonicalize-place-notation "-16.X.14-6X1" :stage 6))
     ⇒ ("x1x4,6" t)
 (multiple-value-list
   (canonicalize-place-notation "-3-[134265]-1T-" :stage 12))
     ⇒ ("x3x(24)x1x" nil)
Variable: *cross-character*

The character used by default as “cross” when writing place notation. Must be a character designator for one of #\x, #\X or #\-. Its initial default value is a lower case ‘x’, #\x.


Previous: , Up: Fundamental Types   [Contents][Index]