unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Higher order modules: a first stab
@ 2012-03-09 13:51 Ian Price
  2012-03-21 19:16 ` Ludovic Courtès
  0 siblings, 1 reply; 2+ messages in thread
From: Ian Price @ 2012-03-09 13:51 UTC (permalink / raw)
  To: guile-user


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"




^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Higher order modules: a first stab
  2012-03-09 13:51 Higher order modules: a first stab Ian Price
@ 2012-03-21 19:16 ` Ludovic Courtès
  0 siblings, 0 replies; 2+ messages in thread
From: Ludovic Courtès @ 2012-03-21 19:16 UTC (permalink / raw)
  To: guile-user

Hello,

Sorry for the delay.

This looks nice.

Ian Price <ianprice90@googlemail.com> skribis:

> 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.

Would be cool to see how higher-order module support could be added to
our module system.

Something like:

  (define-module (seq-utils)
    #:require (kar kdr)
    #:export (take drop))

  ...

and:

  (define-module (srfi srfi-1)
    #:use-module ((seq-utils) #:with (car cdr)))

  ...

  (define-module (ice-9 vlist)
    #:use-module ((seq-utils) #:with (vlist-head vlist-tail)))

  ...

  (resolve-module '(seq-utils) #:with (list car cdr))
  => fresh module

  (resolve-module '(seq-utils))
  =| error

WDYT?

Thanks,
Ludo’.




^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2012-03-21 19:16 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-09 13:51 Higher order modules: a first stab Ian Price
2012-03-21 19:16 ` Ludovic Courtès

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).