This page is part of the web mail archives of SRFI 76 from before July 7th, 2015. The new archives for SRFI 76 contain all messages, not just those from before July 7th, 2015.
Thank you for the update. I have some comments and questions on LET below, although even with LET, we can still only express a subset of possible constructors, without a good reason why this subset is special. For this reason, I would still rather do without the LET clause and would still advocate either: - Having just simple SRFI-9 type constructors (my preference), or, - Making the user write the constructor explicitly. This remains a more general solution. Comments: ========= - Calling it LET can be confusing, since it is unlike the usual LET. How about FIELDS-WITH (see next). - The scoping is a bit weird in that references can precede bindings and bindings may not bind following references, e.g. (define-type foo () (fields (x () x-value) ; precedes binding (y () y-value)) (let ((x-value 1))) (init! (r) (display x-value)) ; refers to toplevel x-value (let ((y-value 2)))) Also, in the above, presumably x-value refers to a toplevel binding and not the let-binding?? How about making the scoping follow a more readable block structure such as (some variation of): (define-type foo () (fields-with ((x-value 1) (y-value 2)) (x () x-value) (y () y-value))) (init! (r) (display x-value)) - We can now indeed express the RATIONAL example: (define-type rational (x y) (let ((fields (if (= y 0) (cons 1 0) ; representation of infinity (let ((common (gcd x y))) (cons (/ x common) (/ y common)))) (fields (num immutable (car fields)) (denom immutable (cdr fields))) - As you mention, LET-VALUES would be useful for efficiency in examples such as RATIONAL above. - Even LET-VALUES (unless optimized away) would allocate more intermediate values and presumably be slightly less efficient than an explicit constructor (in pseudocode): (define-type rational (constructor (lambda (x y) (if (= y 0) (instantiate (parent) (num 1) (denom 0)) ; representation of infinity (let ((common (gcd x y))) (instantiate (parent) (num (/ x common)) (denom (/ y common))))))) (fields num denom)) - We can do imperative things, but it is a hack: (define-type foo () (let ((dummy (display "About to allocate a foo")))) (fields x y)) This would be more natural to express in an explicit constructor. - We can express LETREC, but it is a hack, and inefficient without optimization: (define-type foo () (let ((fields (letrec (even? (lambda (n) ......)) (odd? (lambda (n) ......))) (cons even? odd?)))) (fields (method1 () (car fields)) (method2 () (cdr fields)))) This would be more natural to express in an explicit constructor. - The same goes for the following pseudocode for a constructor with case-lambda. It is expressible with LET, but a hack and inefficient: (define-type rational (constructor (case-lambda ((n) .....) ((n d) .....)))) - What would be the "upgrade path" for adding possible extensions to make things like the previous two points less hackish? Should future extensions have to piecemeal add LETREC, BEGIN, etc. clauses as extra syntax, eventually reproducing some sublanguage of standard Scheme? :-) - Some constructors that are still not expressible: ================================================= ;; Conditionally instantiating the parent with different arguments: ;; (actually this specific example can be expressed but would ;; require the test for (= y 0) to be duplicated): (define-type rational (parent finite-rational) (constructor (lambda (x y) (if (= y 0) (instantiate (parent 1 0)) (instantiate (parent x y)))))) ;; Local lexicals: (define-type generated-id (fields symbol) (constructor (let ((count 0)) (lambda () (set! count (+ count 1)) (string->symbol ................))))) ;; Forwarding a variable number of arguments to parent ;; (here called PARENT-APPLY): (define-type rational-with-comment (num . maybe-denom) (parent-apply rational num maybe-denom) (fields comment)) Cheers Andre