unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Ian Price <ianprice90@googlemail.com>
To: guile-user@gnu.org
Subject: Higher order modules: a first stab
Date: Fri, 09 Mar 2012 13:51:51 +0000	[thread overview]
Message-ID: <87obs5991k.fsf@Kagami.home> (raw)


Hi guilers,

I've been musing over the concept of higher order modules (modules
parameterized by other modules) in the back of my mind, and am
occasionally making steps towards implementing it in guile. I think that
with guile's first class modules all the machinery is there, it's just a
question of figuring out the best way to do it. The advantage for users
of guile is that it provides a different, and hopefully useful, form of
code reuse.

Here is the first step towards it that I made.

;;; higher order modules for guile

(define-syntax-parameter provide ; an "export" for `module' forms
  (lambda (stx)
    (syntax-violation 'provide "provide used outside a module form" stx)))

(define-syntax module
  (lambda (stx)
    (syntax-case stx ()
      ((module (params ...) body ...)
       (with-syntax (((tmp ...) (generate-temporaries #'(params ...))))
         #'(lambda (tmp ...)
             (define fresh (make-fresh-user-module))
             (module-use! fresh (resolve-interface '(guile)))
             (save-module-excursion
              (lambda ()
                (set-current-module fresh)
                (let ((export-alist '()))
                  (syntax-parameterize ((provide (syntax-rules ()
                                                   ((provide foo bar (... ...))
                                                    (set! export-alist
                                                          (append (list
                                                                   (cons 'foo foo)
                                                                   (cons 'bar bar)
                                                                   (... ...))))))))
                    (define params tmp) ...
                    body ...
                    (map (lambda (pair)
                           (let ((var (car pair))
                                 (val (cdr pair)))
                             (module-define! fresh var val)))
                         export-alist)))))
             fresh))))))

;; example module
(define stream-utils
  (module (stream-car stream-cdr)
    (define (stream-drop s n)
      (if (zero? n)
          s
          (stream-drop (stream-cdr s) (- n 1))))
    (define (stream-take s n)
      (if (zero? n)
          '()
          (cons (stream-car s)
                (stream-take (stream-cdr s) (- n 1)))))
    (provide stream-drop stream-take)))

;; first stream implementation
;; Stream a = Stream b (b -> a) (b -> Stream a)

(import (rnrs records syntactic))

(define-record-type stream
  (fields val this next))

(define (stream-car stream)
  ((stream-this stream) (stream-val stream)))

(define (stream-cdr stream)
  ((stream-next stream) (stream-val stream)))

(define (constant-stream k)
  (define (next k)
    (make-stream k identity next))
  (next k))

(define naturals
  (letrec ((next (lambda (current)
                   (make-stream (+ 1 current) identity next))))
    (next -1)))

(define stream-module (stream-utils stream-car stream-cdr))
(define stream-take (module-ref stream-module 'stream-take))

(stream-take naturals 10) ;;(0 1 2 3 4 5 6 7 8 9)


;; second stream implementation
(use-modules ((ice-9 streams)
              #:renamer (symbol-prefix-proc 's:)))

(define naturals2 (s:make-stream (lambda (x)
                                   (cons x (1+ x)))
                                 0))

(define stream-module2 (stream-utils s:stream-car s:stream-cdr))
(define stream-take2 (module-ref stream-module2 'stream-take))

(stream-take2 naturals2 10)


Currently, parameterized modules are functions that return a
module, and functions are retrieved by module-ref. This is fine for a
proof of concept, but hopefully I'll have something better integrated
soon.

Thanks to wingo for suggesting the current method of providing exports

-- 
Ian Price

"Programming is like pinball. The reward for doing it well is
the opportunity to do it again" - from "The Wizardy Compiled"




             reply	other threads:[~2012-03-09 13:51 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-09 13:51 Ian Price [this message]
2012-03-21 19:16 ` Higher order modules: a first stab Ludovic Courtès

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87obs5991k.fsf@Kagami.home \
    --to=ianprice90@googlemail.com \
    --cc=guile-user@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).