R6RS records and exports

In this post I asked:

Records conveniently generate a constructure and getters and setters for you.

Is there a way to conveniently export all these generated functions?

I am thinking of generating a helper function so I can copy and paste the exports; this is not ideal of course.

Aziz posted the following solution which works fine on PLT with Andrerui’s fix. I added code to make it in a standard library location:

redefine-record.sls


#!r6rs

;;;; Via comp.lang.scheme "R6RS records and exports"
;;;; By Aziz

;;; redefine-record.sls

(library
 (redefine-record redefine-record)
 (export redefine-record-type)
 (import (rnrs))

 (define-syntax redefine-record-type
   (syntax-rules ()
     [(_ record-name)
      (begin
        (define-syntax m
          (lambda (x)
            (define (fmt s1 stx . s*)
              (datum->syntax stx
                             (string->symbol
                              (apply string-append
                                     s1
                                     (symbol->string (syntax->datum stx))
                                     s*))))
            (define (enumerate i j)
              (if (= i j) '() (cons i (enumerate (+ i 1) j))))
            (syntax-case x ()
              [(_ ctxt)
               (let* ([rtd (record-type-descriptor
                            record-name)]
                      [f* (record-type-field-names rtd)]
                      [rcd (record-constructor-descriptor
                            record-name)])
                 (with-syntax ([make-T (fmt "make-" #'ctxt)]
                               [T? (fmt "" #'ctxt "?")]
                               [(n* (... ...))
                                (enumerate 0 (vector-length f*))]
                               [#(T-ref* (... ...))
                                (vector-map
                                 (lambda (x)
                                   (fmt "" #'ctxt "-" (symbol->string
                                                       x)))
                                 f*)])
                   #'(begin
                       (define make-T
                         (record-constructor
                          (record-constructor-descriptor
                           record-name)))
                       (define T?
                         (record-predicate
                          (record-type-descriptor
                           record-name)))
                       (define T-ref*
                         (record-accessor
                          (record-type-descriptor record-name)
                          n*))
                       (... ...))))])))
        (m record-name))])))


t1.sls


#!r6rs

;;;; Via comp.lang.scheme "R6RS records and exports"
;;;; By Aziz

;;; t1.sls

(library
 (redefine-record t1)
 (export M)
 (import (rnrs))

 (define-record-type M
   (fields x y z)))


t2.ss


#!r6rs

;;;; Via comp.lang.scheme "R6RS records and exports"
;;;; By Aziz and Andreuri

;;; t2.ss

(import (rnrs) (for (redefine-record t1) expand run) (redefine-record redefine-record))

(redefine-record-type M)

(define x (make-M 12 13 14))
(display (list x (M? x) (M-x x)))
(newline)

Run this to see it work:


plt-r6rs t2.sls
=> {#(struct:M 12 13 14) #t 12}

win-control

OLE, Internet Explorer and raw windows automation library for Gambit-C on Windows platforms

Inspired by Watir on Ruby, this library brings the same capabilities and more to the high-performing Gambit Scheme implementation. Now you can write automated test scripts or automate Windows application tasks in beautiful Scheme code and compile it all into a standalone exe file.

(via comp.lang.scheme)

Random Art

Suppose we take an expression in x and y, built by nesting simple primitives: product, average, sin(pi*_), and cos(pi*_). These four operations map arguments in the range -1 to 1 to results in this same range. Thus, at any point with -1 <= x,y <= 1, our expression built from these primitives will return a value between -1 and 1. By scaling the answer to a grayscale value 0-255, we can plot the function in this 2-by-2 square. (From three such expressions, we can get red, green, and blue values for each point.)

What you get is some very nifty art!
(via PLT)
Addendum: 03/11/09
Noel posted some PLT Scheme code for implementation here:

#lang scheme/gui
(define (make-plotter drawing-fn size)
  (lambda (canvas dc)
    (for* ((x (in-range size))
           (y (in-range size)))
      (let* ([intensity (inexact->exact (round (* (/ (add1
                                                      (drawing-fn x y)) 2) 255)))]
             [colour (make-object color% intensity intensity intensity)])
        ;;(printf "~a ~a ~a\n" intensity x y)
        (send dc set-pen colour 1 'solid)
        (send dc draw-point x y)))))
(define (draw-grayscale size drawing-fn)
  (define frame (new frame%
                     [label "Random Art"]
                     [width size]
                     [height size]))
  (define canvas (new canvas%
                      [parent frame]
                      [paint-callback (make-plotter drawing-fn size)]))
  (send frame show #t))
(define (example1 x y)
  ;; some random stuff
  (sin (* (sin (* (cos x) y))
          (cos (*
                (sin (* (sin y) (cos x)))
                (cos (*  (cos (* y x)))))))))
(define (example2 x y)
  (if (> x 200)
      1
      -1))
;;(draw-grayscale 400 example1)

How PLTCOLLECTS works in PLT Scheme

R6RS Scheme systems are composed of code artifacts that are either libraries or top-level-programs. Libraries simply map to directories. In PLT Scheme, you can configure the library search path by configuring the PLTCOLLECTS environmental variable.
Having configured it and not getting results that I had expected, I asked about what I was doing wrong and got a great explanation here. It is pasted below.

The path-list function does something that is common with environment variables that specify paths: you have a string of several paths, separated by a “:”, which are searched in order. In addition, an empty path means “splice the default here”. So you get:
“/foo:/bar” — look in /foo and then in /bar
“/foo:/bar:” — look in /foo, then in /bar, and then in the default
“:/foo:/bar” — look in the default, then /foo then /bar
“/foo::/bar” — look in /foo then the default, then /bar
The last example shows why it’s useful — it allows you to both override PLT collections, as well as specify collections that could be overriden by PLT collections. For example, the first is useful if you want to try patching libraries, and the second is useful if you want to add a library that is added to a later version of PLT and you want to use it now but not when you upgrade.
Finally, on windows, the path separator character is “;” instead of a colon. (And remember the possible pitfalls with backslashes, or just use forward slashes.)

Hopefully that detail gets added to the documentation; it wasn’t obvious from reading it.