Associated with every vector is a seevec. If v is a vector then (see v) is the corresponding seevec. (vector-ref (see v) k) = (see (vector-ref v k)) and (vector-length (see v)) = (vector-length v). (vector-set! (see v) n x) and (vector-fill! (see v) x) have no effect. (vector->list (see v)) = (see (vector->list v)). If b is a list then (list->vector (see b)) = (see (list->vector b)).
For every string there is a corresponding seestring.
If s is a string then (see s) is the corresponding seestring.
(string-length (see s)) = (string-length s).
(string-ref (see s) k) = (string-ref s k).
(string-set! (see s) k c) has no effect and should signal an error.
If x is one of string=?, string-ci=?, string<?, string>?, string<=?, string>=?, string-ci<?, string-ci>?, sring-ci<=?, string-ci>=?
and strx1 is either (see str1) or str1
and strx2 is either (see str2) or str2
then (x strx1 strx2) = (x str1 str2).
(substring (see str) k l) = (substring str k l).
(read-only str) = (see str).
For all x, (see (see x)) = (see x).
I think that (pair? (see x)) = (pair? x), (vector? (see x)) = (vector? x) and (string? (see x)) = (string? x). This is for further study.
We define see? thus: (see? x) = (eqv? x (see x)).
This predicate corresponds to “sensory” in Keykos.
Literals produce sensory values but primitive constructors don’t:
(see? '(0 . 0)) but not (see? (cons 0 0)).
(see? #(3 5 7)) but not (see? (vector 3 1)).
(see? "gx") but not (see? (string #\g #\x)).
It is no longer necessary as an additional language rule to declare it an error to modify the value of a literal.
If (or (procedure? x) (port? x)) then (eq? (see x) '()).
If (or (boolean? x) (symbol? x) (char? x) (number? x))
then (eq? x (see x)).
(see '()) = '().
Associated with each vector is a rovec of the same length and members.
If v is a vector then (read-only v) is the corresponding rovec.
(length (read-only v)) = (length v)
(vector-ref (read-only v) k) = (vector-ref v k), unlike (see v)!
(vector-set! (read-only v) k x) and (vector-fill! (read-only v) x) have no effect and may signal an error.
Read-only could also be logically applied to pairs but we don’t need that. Do we have “If (eq? x y) then (eqv? x y)”? Not for NaN.
Phrases such as “fresh locations holding undefined values” in R5RS must be somehow qualified to insure that those values are not my secrets—even that they are statistically independent of my secrets. They must also not convey the ability to step on my secrets. In the jargon of denotational semantics, bottom must be relativized. If the jargon of OS’es your bug must not corrupt my world. We must make some statements about erroneous programs.
Of course there are really pointers underneath.
The introduction of the environment seems to miss the point that the same occurrence of an expression is evaluated in different environments at different times. I don’t see a clear stance as to whether environments are mutable. Being extendable is less dangerous than being mutable. The text in eval
Integrate with this.
(define fc (let* ( (factory-seal (new-seal)) (fac-seal (car factory-seal)) (fac-unseal (cadr factory-seal))) (lambda (n) (let* ( (seal (new-seal)) (sealer (car seal)) (unsealer (cadr seal)) (components (vector n '()))) (lambda args (case n ((1) ; Install a sensory component. (vector-set! components (cadr args) (see (caddr args)))) ((2) ; Install another requestor’s key (if (fac-unseal (caddr args)) (vector-set! components (cadr args) (caddr args)))) ((3) ; Seal factory and return requestor’s key. (let ((requestor (lambda args (eval (vector-ref components 0) (fac-seal requestor) requestor)
Still there remains a possible advantage to my scheme. Since car can operate on either a pair or seepair, readers of a list need not discriminate between the two and a list builder can construct mutable lists, and indeed looped lists which behave as ordinary lists to the reader. In Rees’ Scheme looped lists can be constructed but extra logic is required by the reader. I do not now know how to combine the advantages of the two schemes. Another advantage of my scheme is that I can grant read-only access to a mutable structure. I retain the ability to mutate the structure even as you navigate it. This is dangerous, but fundamental.
I think that seeprocs are also feasible. The environment of the procedure would be weakened (made sensory). The cleanliness of Scheme semantics makes this feasible. I am not sure of the ramifications on implementations but I would suppose that the trip up the dynamic chain of environments would include a read-only check at each step. If a bit were allocated within the address of environments, then this extra cost would be about one very efficient machine op (a register or) per static nest depth per variable reference.