unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* R6RS Libraries
@ 2007-02-06 15:55 Ludovic Courtès
  0 siblings, 0 replies; 19+ messages in thread
From: Ludovic Courtès @ 2007-02-06 15:55 UTC (permalink / raw)
  To: Guile-Devel

Hi,

FWIW, I started an implementation of R6RS' bytevector API.  It is
available in my Arch archive [0], in the branch named
`guile-r6rs-libs--devo--0'.

Just letting you know so that we avoid duplicating this (tedious) work.
;-)

Thanks,
Ludovic.

[0] http://www.laas.fr/~lcourtes/software/arch-2006/


_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel


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

* Re: r6rs libraries
       [not found]             ` <877i4z89jy.fsf@gnu.org>
@ 2009-01-26  0:27               ` Julian Graham
  2009-01-27 10:51                 ` Andy Wingo
  0 siblings, 1 reply; 19+ messages in thread
From: Julian Graham @ 2009-01-26  0:27 UTC (permalink / raw)
  To: guile-devel

Hi everyone,

(Switching this conversation to guile-devel from guile-user, since it
seems more appropriate to this list...)

Alright, so I've been studying the van Tonder and Dybvig-Ghuloum
implementations and banging my head against chapter 7 of R6RS, all
with an eye towards mapping them onto Guile's module system, and I
can't for the life of me figure out why the existing implementations
are as complicated as they are.  Maybe some more advanced Schemers
than I can shed some light on the following:

* Import and export levels seem to be a fancy way of notifying the
library system of the time at which a library needs to be
loaded/evaluated -- that is, if you import something from [library
foo] for the "expand phase" of [library bar] you've got to evaluate
(i.e., convert to a Guile module) the S-exp for [library foo] before
you can evaluate the S-exp for [library bar].  The levels system is
simply a numerical way of encapsulating this information, but the
proper order of evaluation can also be inferred by inspecting the
import- and export-specs of the libraries being loaded -- i.e., if the
header of [library bar] specifies an import of anything from [library
foo], no matter at what "level," it's a safe move to evaluate [library
foo] (if you haven't already done so) before finishing the evaluation
of [library bar].  Is that right?

* R6RS says that a library's imports need to be visited/instantiated
at the time the bindings they export are "referenced."  Why?  As
above, why can't they be visited/instantiated at the time the imports
for the importing library are processed?  Is there any noticeable
difference to the user?  Or do you guys read R6RS 7.2 to mean that the
side-effects of top-level expressions absolutely need to happen at a
time determined by the import level?

* R6RS also says that implementations are free to visit/instantiate
libraries more or less often than is required by the import-export
graph.  Why would you want to visit/instantiate a library more than
once?  Why not just do it once, turn it into a module, and cache it?
Andy Wingo noted that some implementations do a fresh visit for every
phase (and that it's problematic), but I can't even see why you'd want
to if the spec lets you off the hook for it.

I understand that the authors of the reference implementation
re-created a lot of machinery out of whole cloth since they were
avoiding assumptions about features of their target Scheme platforms,
but, man, both van Tonder and Dybvig-Ghuloum look like overkill for
Guile.  Am I missing a major piece of understanding here?


Regards,
Julian




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

* Re: r6rs libraries
  2009-01-26  0:27               ` r6rs libraries Julian Graham
@ 2009-01-27 10:51                 ` Andy Wingo
  2009-01-27 20:09                   ` Ludovic Courtès
  2009-01-28 17:26                   ` Julian Graham
  0 siblings, 2 replies; 19+ messages in thread
From: Andy Wingo @ 2009-01-27 10:51 UTC (permalink / raw)
  To: Julian Graham; +Cc: guile-devel

Hi Julian,

On Mon 26 Jan 2009 01:27, Julian Graham <joolean@gmail.com> writes:

> Maybe some more advanced Schemers than I can shed some light on the
> following:

Well, that's not me, but I'll join you in fumbling for a solution :-)

> The levels system is simply a numerical way of encapsulating this
> information, but the proper order of evaluation can also be inferred
> by inspecting the import- and export-specs of the libraries being
> loaded

I think you're right, yes. I think that the approach that you describe
has been called "Implicit phasing" by Ghuloum and Dybvig. They have a
paper about it, "Implicit phasing in R6RS libraries" -- but I haven't
been able to find it freely on the web. ACM fail.

> * R6RS says that a library's imports need to be visited/instantiated
> at the time the bindings they export are "referenced."  Why?  As
> above, why can't they be visited/instantiated at the time the imports
> for the importing library are processed?

I could not find the quote that you referred to here -- I think what I
can tell (from 7.2):

    If any of a library’s definitions are referenced at phase 0 in the
    expanded form of a program, then an instance of the referenced
    library is created for phase 0 before the program’s definitions and
    expressions are evaluated. This rule applies transitively: if the
    expanded form of one library references at phase 0 an identifier
    from another library, then before the referencing library is
    instantiated at phase n, the referenced library must be instantiated
    at phase n. When an identifier is referenced at any phase n greater
    than 0, in contrast, then the defining library is instantiated at
    phase n at some unspecified time before the reference is evaluated.
    Similarly, when a macro keyword is referenced at phase n during the
    expansion of a library, then the defining library is visited at
    phase n at some unspecified time before the reference is evaluated.

So what this says to me is that:

  (1) At phase 0, libraries that you need to run a /program/ are
      instantiated before the program is run.

  (2) At phase n > 0, we do not specify when libraries are imported.

> Is there any noticeable difference to the user?

Dunno, to me it sounds like a concession, that side effects from loading
libraries occur before side effects from running a program; but that for
meta-levels things are left unspecified.

> Or do you guys read R6RS 7.2 to mean that the side-effects of
> top-level expressions absolutely need to happen at a time determined
> by the import level?

No.

So, for some of your other questions here's section 7.5 of the
rationale:

    7.5. Instantiation and initialization                     
                                                              
    Opinions vary on how libraries should be instantiated and
    initialized during the expansion and execution of library bodies,
    whether library instances should be distinguished across phases, and
    whether levels should be declared so that they constrain identifier
    uses to particular phases.
                                                              
As I read this, it means that at least PLT wanted the separate
instantiation model, and Chez wanted single-instantiation, implicit
phasing.

    This report therefore leaves considerable latitude to
    implementations, while attempting to provide enough guarantees to
    make portable libraries feasible.

So from 7.2 of R6RS itself:

    An implementation may distinguish instances/visits of a library for
    different phases or to use an instance/visit at any phase as an
    instance/visit at any other phase.

Which is to say, "we allow single instantiation" -- as Guile modules
are.

    An implementation may further expand each library form with distinct
    visits of libraries in any phase and/or instances of libraries in
    phases above 0.

Which is to say, "we also allow the PLT model, explicitly."

    An implementation may create instances/visits of more libraries at
    more phases than required to satisfy references.

This is an odd one. I suppose what it means is that if you need a macro
from library A to expand library B, but you don't need library A at
runtime, the spec allows library A to be /instantiated/ at runtime.

    When an identifier appears as an expression in a phase that is
    inconsistent with the identifier’s level, then an implementation
    may raise an exception either at expand time or run time, or it may
    allow the reference.

So, furthermore, it seems that not only may library A be instantiated at
runtime, /it may be in library B's "import list" as well/. This is what
happens with Guile's current module semantics.

    Thus, a library whose meaning depends on whether the instances of a
    library are distinguished or shared across phases or library
    expansions may be unportable.

Indeed, indeed.

> I understand that the authors of the reference implementation
> re-created a lot of machinery out of whole cloth since they were
> avoiding assumptions about features of their target Scheme platforms,
> but, man, both van Tonder and Dybvig-Ghuloum look like overkill for
> Guile.  Am I missing a major piece of understanding here?

I don't think you're missing anything big, no. I hadn't fully poked into
these implementations -- if it is easier just to build something on top
of Guile's modules than to retrofit guile's modules into one of their
implementations, then that's all the better, right?

Cheers,

Andy
-- 
http://wingolog.org/




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

* Re: r6rs libraries
  2009-01-27 10:51                 ` Andy Wingo
@ 2009-01-27 20:09                   ` Ludovic Courtès
  2009-01-28 17:26                   ` Julian Graham
  1 sibling, 0 replies; 19+ messages in thread
From: Ludovic Courtès @ 2009-01-27 20:09 UTC (permalink / raw)
  To: guile-devel

Hello!

Andy Wingo <wingo@pobox.com> writes:

> So from 7.2 of R6RS itself:
>
>     An implementation may distinguish instances/visits of a library for
>     different phases or to use an instance/visit at any phase as an
>     instance/visit at any other phase.
>
> Which is to say, "we allow single instantiation" -- as Guile modules
> are.

[...]

>
>     When an identifier appears as an expression in a phase that is
>     inconsistent with the identifier’s level, then an implementation
>     may raise an exception either at expand time or run time, or it may
>     allow the reference.
>
> So, furthermore, it seems that not only may library A be instantiated at
> runtime, /it may be in library B's "import list" as well/. This is what
> happens with Guile's current module semantics.

These both come as a surprise to me, as I had always thought R6RS was
much stricter about phase separation.  That's good news for "pure
interpreters"; extra work would still be needed to handle phases > 0 in
the compiler.

Thanks for the detailed reading!

Ludo'.





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

* Re: r6rs libraries
  2009-01-27 10:51                 ` Andy Wingo
  2009-01-27 20:09                   ` Ludovic Courtès
@ 2009-01-28 17:26                   ` Julian Graham
  2009-02-16 18:35                     ` Julian Graham
  1 sibling, 1 reply; 19+ messages in thread
From: Julian Graham @ 2009-01-28 17:26 UTC (permalink / raw)
  To: Andy Wingo; +Cc: guile-devel

Hi Andy,

Thanks so much for helping me parse!


> I think you're right, yes. I think that the approach that you describe
> has been called "Implicit phasing" by Ghuloum and Dybvig. They have a
> paper about it, "Implicit phasing in R6RS libraries" -- but I haven't
> been able to find it freely on the web. ACM fail.

Oooh -- if you do find it, let me know.  That sounds interesting.


> I could not find the quote that you referred to here -- I think what I
> can tell (from 7.2):

(Yes, that was the bit I was referring to.  Sorry about that.)

One thing that occurred to me, though, while I was brooding on this,
is the case in which you've got two bindings that share the same name
that are both imported (from different libraries) into library foo --
one's a syntax transformer used to expand library foo, the other's a
function used by library foo at runtime.  R6RS seems designed to
address cases like this so that they work out, you know, hygienically.
 And I think Guile's module system can handle this as well, though it
may require some slightly weird designs.

E.g., one thing I was thinking of trying was mapping an R6RS library
onto *two* generated Guile modules: One to represent the expansion
environment, and one to represent the environment of the expanded
library in which the library bindings and top-level expressions are
actually evaluated (I guess this is the same as the runtime
environment?).  The first module's imports would include bindings
required for expansion; the second's would include the stuff for
runtime.


> I don't think you're missing anything big, no. I hadn't fully poked into
> these implementations -- if it is easier just to build something on top
> of Guile's modules than to retrofit guile's modules into one of their
> implementations, then that's all the better, right?

Strongly agree.


Regards,
Julian




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

* Re: r6rs libraries
  2009-01-28 17:26                   ` Julian Graham
@ 2009-02-16 18:35                     ` Julian Graham
  2009-02-16 20:58                       ` Andreas Rottmann
                                         ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Julian Graham @ 2009-02-16 18:35 UTC (permalink / raw)
  To: guile-devel

Hi Guilers,

Just wanted to give an update on the status of the library system I've
been working on:

* As per the discussion above, my implementation uses an implicit
phasing approach (i.e., it doesn't do multiple instantiation) along
with `(ice-9 syncase)' to handle expand-time evaluation --
specifically, by way of evaluation environments based on on-the-fly
creation of custom module interfaces.  I wasn't able to find
Abdulaziz's ACM paper, but his "formal comment" on the subject of R6RS
phasing [1] was informative.  (In fact, a lot of the formal comments
were handy: [2].)  I haven't yet delved into how severe the breakage
is where there are differences between Guile's `syntax-case' and
R6RS's, but I'm hoping it's, you know, mild.

* Given the above, my current implementation is hovering at about 200
lines, whereas the current reference implementations, because they
don't presume an existing macro or module system, are several orders
of magnitude larger.  Thanks are due to Tom Lord (and everyone else
who designed Guile's module / interface system) for making this
possible, if not downright easy.

* At the moment, R6RS libraries can "import" Guile modules directly,
but the reverse is not true, partly because I can't figure out a good
way to map version information onto the filesystem in a way that
Guile's module system can understand.  My initial thought was to do it
such that a library's version would map to its module name, a la:

(library (foo bar baz (6))

would live in

/foo/bar/6/baz.scm

...but Guile doesn't like numbers in the module name.  Right now I'm
trying to think of way to do a transformation on a library expression
such that multiple versions of the same library could live in the same
Guile module and be accessed individually by some kind of manifest at
"use" time, but I can't figure out what that module name and the
extra, associated API should look like.

* It would be cool if the module system had hooks of some sort to
allow it to receive hints about locating modules.

* The "party balloons" example from the R6Rs is working, at least
intermittently.  The "quotient-and-remainder" example is almost there.


Regards,
Julian

[1] - http://www.r6rs.org/formal-comments/comment-123.txt
[2] - http://www.r6rs.org/formal-comments/comment-92.txt




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

* Re: r6rs libraries
  2009-02-16 18:35                     ` Julian Graham
@ 2009-02-16 20:58                       ` Andreas Rottmann
  2009-02-18  6:08                         ` Julian Graham
  2009-02-17 21:43                       ` Ludovic Courtès
  2009-03-04  5:23                       ` Julian Graham
  2 siblings, 1 reply; 19+ messages in thread
From: Andreas Rottmann @ 2009-02-16 20:58 UTC (permalink / raw)
  To: Julian Graham; +Cc: guile-devel

Julian Graham <joolean@gmail.com> writes:

> * At the moment, R6RS libraries can "import" Guile modules directly,
> but the reverse is not true, partly because I can't figure out a good
> way to map version information onto the filesystem in a way that
> Guile's module system can understand.  My initial thought was to do it
> such that a library's version would map to its module name, a la:
>
> (library (foo bar baz (6))
>
> would live in
>
> /foo/bar/6/baz.scm
>
> ...but Guile doesn't like numbers in the module name.
>
All R6RS implementations I'm somewhat familiar with (Ikarus, PLT,
Ypsilon) do some kind of name mangling when library names contain
"special" characters; e.g. (srfi :6 and-let*) maps to
"srfi/%3a2/and-let%2a.sls", at least for Ikarus (%-escaped hex of the
utf-8 encoding, IIRC).

Nice to see Guile is on the way to R6RS interoperability!

Regards, Rotty




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

* Re: r6rs libraries
  2009-02-16 18:35                     ` Julian Graham
  2009-02-16 20:58                       ` Andreas Rottmann
@ 2009-02-17 21:43                       ` Ludovic Courtès
  2009-02-18  5:37                         ` Julian Graham
  2009-03-04  5:23                       ` Julian Graham
  2 siblings, 1 reply; 19+ messages in thread
From: Ludovic Courtès @ 2009-02-17 21:43 UTC (permalink / raw)
  To: guile-devel

Hi Julian,

Thanks for the nice report!

Julian Graham <joolean@gmail.com> writes:

> * At the moment, R6RS libraries can "import" Guile modules directly,
> but the reverse is not true, partly because I can't figure out a good
> way to map version information onto the filesystem in a way that
> Guile's module system can understand.  My initial thought was to do it
> such that a library's version would map to its module name, a la:
>
> (library (foo bar baz (6))
>
> would live in
>
> /foo/bar/6/baz.scm
>
> ...but Guile doesn't like numbers in the module name.

There are many other things that it doesn't like in module names,
typically any standard top-level binding (`eval', `+', etc.) can't be
used as a module name component.  That plus "special" chars means you
really need some name mangling, as Andreas suggested.

As for version numbers, you could have a mapping like the following:

  R6RS Name             Guile Name

  (foo bar)      -->    (foo bar)
  (foo bar (6))  -->    (foo bar version-6)

(Given the recursive name space, this would allow the implementation of
several versions in a single file.  In this example, `version-6' in
`(foo bar)' just has to be bound to a module.)

Thanks,
Ludo'.





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

* Re: r6rs libraries
  2009-02-17 21:43                       ` Ludovic Courtès
@ 2009-02-18  5:37                         ` Julian Graham
  2009-02-18  8:53                           ` Ludovic Courtès
  0 siblings, 1 reply; 19+ messages in thread
From: Julian Graham @ 2009-02-18  5:37 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

>  R6RS Name             Guile Name
>
>  (foo bar)      -->    (foo bar)
>  (foo bar (6))  -->    (foo bar version-6)
>
> (Given the recursive name space, this would allow the implementation of
> several versions in a single file.  In this example, `version-6' in
> `(foo bar)' just has to be bound to a module.)

Wait, you've lost me -- the recursive name space?  I thought Guile
requires that the "tail car" of the module name map to an actual
filename on disk when searching for modules.




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

* Re: r6rs libraries
  2009-02-16 20:58                       ` Andreas Rottmann
@ 2009-02-18  6:08                         ` Julian Graham
  2009-02-18 14:27                           ` Andreas Rottmann
  0 siblings, 1 reply; 19+ messages in thread
From: Julian Graham @ 2009-02-18  6:08 UTC (permalink / raw)
  To: Andreas Rottmann; +Cc: guile-devel

Hi Rotty,

> All R6RS implementations I'm somewhat familiar with (Ikarus, PLT,
> Ypsilon) do some kind of name mangling when library names contain
> "special" characters; e.g. (srfi :6 and-let*) maps to
> "srfi/%3a2/and-let%2a.sls", at least for Ikarus (%-escaped hex of the
> utf-8 encoding, IIRC).

Hey, wait, I'm dumb -- why does :6 map to UTF-8 0x3A2?

On a sort of related note, though, I was experimenting with acceptable
symbol characters / filenames, and .6 seems to work as either.  Any
reason Guile couldn't map the R6RS library reference (a b c (1 2 3))
to Guile module (a b .1 .2 .3 c)?


Regards,
Julian





>
> Nice to see Guile is on the way to R6RS interoperability!
>
> Regards, Rotty
>




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

* Re: r6rs libraries
  2009-02-18  5:37                         ` Julian Graham
@ 2009-02-18  8:53                           ` Ludovic Courtès
  2009-02-18 21:16                             ` Andy Wingo
  0 siblings, 1 reply; 19+ messages in thread
From: Ludovic Courtès @ 2009-02-18  8:53 UTC (permalink / raw)
  To: guile-devel

Hi,

Julian Graham <joolean@gmail.com> writes:

>>  R6RS Name             Guile Name
>>
>>  (foo bar)      -->    (foo bar)
>>  (foo bar (6))  -->    (foo bar version-6)
>>
>> (Given the recursive name space, this would allow the implementation of
>> several versions in a single file.  In this example, `version-6' in
>> `(foo bar)' just has to be bound to a module.)
>
> Wait, you've lost me -- the recursive name space?  I thought Guile
> requires that the "tail car" of the module name map to an actual
> filename on disk when searching for modules.

Look for `nested-ref' in `boot-9.scm'.  That's why standard binding
names can't be used in module names (e.g., a module can't be named
`(foo bar eval)').

Thanks,
Ludo'.





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

* Re: r6rs libraries
  2009-02-18  6:08                         ` Julian Graham
@ 2009-02-18 14:27                           ` Andreas Rottmann
  0 siblings, 0 replies; 19+ messages in thread
From: Andreas Rottmann @ 2009-02-18 14:27 UTC (permalink / raw)
  To: Julian Graham; +Cc: guile-devel

Julian Graham <joolean@gmail.com> writes:

> Hi Rotty,
>
>> All R6RS implementations I'm somewhat familiar with (Ikarus, PLT,
>> Ypsilon) do some kind of name mangling when library names contain
>> "special" characters; e.g. (srfi :6 and-let*) maps to
>> "srfi/%3a2/and-let%2a.sls", at least for Ikarus (%-escaped hex of the
>> utf-8 encoding, IIRC).
>
> Hey, wait, I'm dumb -- why does :6 map to UTF-8 0x3A2?
>
Oh, sorry, typo: it should have been (srfi :2 and-let*).

Rotty




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

* Re: r6rs libraries
  2009-02-18  8:53                           ` Ludovic Courtès
@ 2009-02-18 21:16                             ` Andy Wingo
  0 siblings, 0 replies; 19+ messages in thread
From: Andy Wingo @ 2009-02-18 21:16 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

Hi,

On Wed 18 Feb 2009 09:53, ludo@gnu.org (Ludovic Courtès) writes:

> Julian Graham <joolean@gmail.com> writes:
>
>> Wait, you've lost me -- the recursive name space?  I thought Guile
>> requires that the "tail car" of the module name map to an actual
>> filename on disk when searching for modules.
>
> Look for `nested-ref' in `boot-9.scm'.  That's why standard binding
> names can't be used in module names (e.g., a module can't be named
> `(foo bar eval)').

We should really fix this -- there's no reason that modules and
variables share the same obarray. This nastiness has bit me a number
of times. (Of course, a module could be in a variable obarray -- but it
shouldn't be by default.)

Andy
-- 
http://wingolog.org/




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

* Re: r6rs libraries
  2009-02-16 18:35                     ` Julian Graham
  2009-02-16 20:58                       ` Andreas Rottmann
  2009-02-17 21:43                       ` Ludovic Courtès
@ 2009-03-04  5:23                       ` Julian Graham
  2009-03-04  8:39                         ` Ludovic Courtès
  2 siblings, 1 reply; 19+ messages in thread
From: Julian Graham @ 2009-03-04  5:23 UTC (permalink / raw)
  To: guile-devel

Hi Guilers,

R6RS libraries updates!

* I'm pleased to report that both the balloons example and the
quotient+remainder macro example are working, which I'm going to take
as more or less a vindication of the module environment-based implicit
phasing approach I've been using.  (I didn't quite trust it at first,
but it turns out that when you call `syncase' in the right context, it
does exactly what you want it to, even when it comes to modules!)

* The on-disk directory organization I've been using for the interim
(and around which I've written a rudimentary library load mechanism)
prefixes version numbers with periods.  E.g., `(foo bar baz (6))' ->
foo/bar/.6/baz.scm.  This seems relatively portable and would work
reasonably well for a mapping of library hierarchies onto Guile module
directories -- but I'm no longer sure that libraries and modules need
to co-exist directly.  It might be saner to offer a method of
tranforming a library expression into a regular Guile module by
"wrapping" it with a module declaration and then storing it on disk in
a traditional location -- e.g., the library name:

(foo bar baz (6))

...would be live in

$GUILE_LOAD_PATH/ice-9/r6rs-libraries/foo/bar/baz-6.scm

...and could be imported using either `(import (foo bar baz (6))' or
`(use-modules (ice-9 r6rs-libraries foo bar baz-6))'.  What do people
think?  (Of course, this still leaves open the question of how to
handle version-matching...)

I'm going to clean things up a bit and then I'll post some code.


Regards,
Julian




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

* Re: r6rs libraries
  2009-03-04  5:23                       ` Julian Graham
@ 2009-03-04  8:39                         ` Ludovic Courtès
  2009-03-04 22:51                           ` Julian Graham
  0 siblings, 1 reply; 19+ messages in thread
From: Ludovic Courtès @ 2009-03-04  8:39 UTC (permalink / raw)
  To: guile-devel

Hi Julian,

Julian Graham <joolean@gmail.com> writes:

> * I'm pleased to report that both the balloons example and the
> quotient+remainder macro example are working, which I'm going to take
> as more or less a vindication of the module environment-based implicit
> phasing approach I've been using.  (I didn't quite trust it at first,
> but it turns out that when you call `syncase' in the right context, it
> does exactly what you want it to, even when it comes to modules!)

Good news!

> * The on-disk directory organization I've been using for the interim
> (and around which I've written a rudimentary library load mechanism)
> prefixes version numbers with periods.  E.g., `(foo bar baz (6))' ->
> foo/bar/.6/baz.scm.

But dot files are traditionally "hidden" on Unices.  Why not go with
`foo/bar/6/baz.scm'?

> (foo bar baz (6))
>
> ...would be live in
>
> $GUILE_LOAD_PATH/ice-9/r6rs-libraries/foo/bar/baz-6.scm
>
> ...and could be imported using either `(import (foo bar baz (6))' or
> `(use-modules (ice-9 r6rs-libraries foo bar baz-6))'.  What do people
> think?  (Of course, this still leaves open the question of how to
> handle version-matching...)

The `r6rs-libraries' part of the module name is just a matter of load
path.  The important thing here is that both `import' and `use-modules'
do the right thing.  Then I would not force R6RS module writers to store
them under `ice-9/r6rs-libraries' as this is inconvenient and doesn't
provide any advantage (AFAICS).

Thanks!

Ludo'.





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

* Re: r6rs libraries
  2009-03-04  8:39                         ` Ludovic Courtès
@ 2009-03-04 22:51                           ` Julian Graham
  2009-03-06 23:39                             ` Ludovic Courtès
  0 siblings, 1 reply; 19+ messages in thread
From: Julian Graham @ 2009-03-04 22:51 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

Hi Ludovic,

> But dot files are traditionally "hidden" on Unices.  Why not go with
> `foo/bar/6/baz.scm'?

Because my initial plan was to make it possible to have R6RS libraries
coexist with Guile modules, using the same directory layout and load
system -- and, as per our earlier discussion, numbers can't be part of
module names.

> The `r6rs-libraries' part of the module name is just a matter of load
> path.  The important thing here is that both `import' and `use-modules'
> do the right thing.  Then I would not force R6RS module writers to store
> them under `ice-9/r6rs-libraries' as this is inconvenient and doesn't
> provide any advantage (AFAICS).

Well, it depends on what we plan to support.  Here's what I've got
implemented so far:

`import' (and the `import' specification in the header of a library
expression) can locate Guile modules by delegating to Guile's module
system.  If this fails, the system will attempt to fulfill the import
requirement by loading library expressions from disk as per the
directory layout I described earlier.

What's not clear to me is:

* Should `use-modules' be able to locate and load (and evaluate) R6RS
library expressions?  If so, where should these modules be stores and
how should they be named -- specifically with regard to version
specifiers?

* If both `use-modules' and `import' can load the same R6RS library,
the one of them will need to be extended to understand the syntax of
the other -- i.e., `use-modules' would need to be able to understand
the `library' form or `import' would need to be able to strip off any
"module wrapper" we'd add to a library to make it loadable via
`use-modules'.


Regards,
Julian




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

* Re: r6rs libraries
  2009-03-04 22:51                           ` Julian Graham
@ 2009-03-06 23:39                             ` Ludovic Courtès
  2009-03-07  0:43                               ` Julian Graham
  0 siblings, 1 reply; 19+ messages in thread
From: Ludovic Courtès @ 2009-03-06 23:39 UTC (permalink / raw)
  To: guile-devel

Hello!

Julian Graham <joolean@gmail.com> writes:

>> But dot files are traditionally "hidden" on Unices.  Why not go with
>> `foo/bar/6/baz.scm'?
>
> Because my initial plan was to make it possible to have R6RS libraries
> coexist with Guile modules, using the same directory layout and load
> system -- and, as per our earlier discussion, numbers can't be part of
> module names.

Hmm, yes, but how about `foo/bar/baz-6.scm'?  Is there a reason to
reject it?

Thanks,
Ludo'..





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

* Re: r6rs libraries
  2009-03-06 23:39                             ` Ludovic Courtès
@ 2009-03-07  0:43                               ` Julian Graham
  2009-03-22 22:30                                 ` Julian Graham
  0 siblings, 1 reply; 19+ messages in thread
From: Julian Graham @ 2009-03-07  0:43 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

> Hmm, yes, but how about `foo/bar/baz-6.scm'?  Is there a reason to
> reject it?

Well, the part of an R6RS library name that comes before its version
is only restricted in that that it must be an identifier -- so a
system that relied on filenames to locate libraries could have trouble
determining whether a file called ice-9-9.scm contained a library
named `(ice-9 (9))' or one named `(ice (9 9))'.

And this also doesn't address the problem of doing version matching as
part of hybrid module / library load process.  After all, I don't
think there are any restrictions in R6RS on where libraries need to be
stored or how they can be located / loaded, so one thing we could do
is ditch the idea that version needs to go into the filename.  Guile
could require that all installed versions of a particular library
would have to reside in the same file, the name of which would be
constructed of the non-version parts of the library name:

foo/bar/baz.scm would contain the code for:

`(foo bar baz (6))'
`(foo bar baz (6 1))'

and

`(foo bar baz (7))'

Using the module system to load that file, a la `(use-modules (foo bar
baz))' would cause, via a hook in the body of that file, all the
library expressions in that file to be stored in a data structure
accessible by the library system for the purposes of subsequent import
and expansion.


Regards,
Julian




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

* Re: r6rs libraries
  2009-03-07  0:43                               ` Julian Graham
@ 2009-03-22 22:30                                 ` Julian Graham
  0 siblings, 0 replies; 19+ messages in thread
From: Julian Graham @ 2009-03-22 22:30 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 3378 bytes --]

Hi Guilers,

Find attached a very early, definitely broken first draft of R6RS
library support.  I was hoping to send this before / during Libre
Planet '09, but AC outlets were scarce (and boozing at The Red Line so
much easier than hacking) so I'm attempting to send this using the
free WiFi on the Acela back to NYC.

As discussed, this version uses the following approach for mapping
Guile's module search / autoloading mechanism onto locating R6RS
libraries: When a user or a library calls `import' with an import
spec,

1. The import spec is unwrapped until an actual library reference is found.
2. If a matching library reference has already been loaded, an
interface meeting the import spec's requirements is created and
returned.
3. Otherwise, `resolve-interface' is called on the name portion of the
library reference.  If a satisficing interface cannot be loaded, the
import fails.
4. Otherwise, the import system expects that either:

   a. The loaded Guile module has registered one or more versions of a
corresponding R6RS library under the library name in the internal
library registry via the `register-library' or `register-from-path'
functions in `(ice-9 r6rs-libraries)'.  If any versions of the library
can be found in the registry, their versions are matched against the
version in the library reference as per R6RS.

   b. The loaded Guile module is a non-R6RS Guile module (e.g.,
`(guile)' or `(ice-9 syncase)').  In this case, it is wrapped in an
R6RS compatibility layer to make it accessible to the library system.

What this means is that `(ice-9 r6rs-libraries)' can automatically
load normal Guile modules, and that R6RS library expressions don't
need to be modified in order to be loadable.  It does require,
however, that every installed set of versions of an R6RS library have
a Guile module that serves as a catalog of sorts.  This catalog module
file might use `register-library' to register the entire library
expression:

(define-module (mystuff mylibrary)
  #:use-module (ice-9 r6rs-libraries))

(register-library
 '(library (mystuff mylibrary (1 2))
    (export foo)
    (import (mystuff myotherlibrary))

    (define (foo) (display "Hello, world!"))))

...or it could use the search path to register a library expression
from an external file:

(define-module (mystuff mylibrary)
  #:use-module (ice-9 r6rs-libraries))

(register-from-path "mystuff/mylibrary.scm.1")
(register-from-path "mystuff/mylibrary.scm.1.2")


This mechanism might need some tweaking, but I think it resolves some
of the issues we were discussing earlier re: users installing R6RS
libraries having to keep them separate from other Guile modules.

If anyone's interested, I've created catalog modules and library
expressions for the bits and pieces of the core set of R6RS libraries
(including `(rnrs base)') necessary for testing, and I'd be happy to
tar them up and make them available somewhere.


Some other points:

* This draft doesn't do any real validation of the `library' form.

* Phased imports for the `define-syntax' form sort of work, but there
are issues with cross-module visibility of bindings for symbols
included in the output of transformers, as discussed here [1].

* Phased imports for the `letrec-syntax' and `let-syntax' forms don't
work at all yet.


Regards,
Julian


[1] - http://lists.gnu.org/archive/html/guile-user/2009-03/msg00015.html

[-- Attachment #2: r6rs-libraries.scm --]
[-- Type: text/x-scheme, Size: 10861 bytes --]

;;; r6rs-libraries.scm --- Support for R6RS libraries

;; Copyright (C) 2009 Free Software Foundation, Inc.
;;
;; This library is free software; you can redistribute it and/or
;; modify it under the terms of the GNU Lesser General Public
;; License as published by the Free Software Foundation; either
;; version 2.1 of the License, or (at your option) any later version.
;; 
;; This library is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;; Lesser General Public License for more details.
;; 
;; You should have received a copy of the GNU Lesser General Public
;; License along with this library; if not, write to the Free Software
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

;;; Author: Julian Graham <julian.graham@aya.yale.edu>
;;; Date: 2009-03-05

;;; Commentary:

(define-module (ice-9 r6rs-libraries)
  :use-module (ice-9 optargs)
  :use-module (ice-9 receive)
  :use-module (ice-9 syncase)
  :use-module (srfi srfi-1)
  :use-module (srfi srfi-2)
  :use-module (srfi srfi-9)
  :use-module (srfi srfi-11)

  :export (import 
	   register-library
	   register-from-path))

(define (library-name library) (list-ref library 1))
(define (library-exports library) (cdr (list-ref library 2)))
(define (library-imports library) (cdr (list-ref library 3)))
(define (library-body library) (cddddr library))

(define library-registry (make-hash-table))
(define interface-registry (make-hash-table))

(define-record-type r6rs-library-type
  (make-r6rs-library name)
  r6rs-library?
  (name r6rs-library-name)
  (exports r6rs-library-exports set-r6rs-library-exports!)
  (module r6rs-library-module set-r6rs-library-module!)
  (interface r6rs-library-interface set-r6rs-library-interface!)
  (parent r6rs-library-parent set-r6rs-library-parent!))

(define* (create-empty-module #:optional name)
  (define module (make-module))
  (set-module-name! module (or name (list (gensym))))
  (let ((interface (make-module)))
    (set-module-name! interface (module-name module))
    (set-module-kind! interface 'interface)
    (set-module-public-interface! module interface))
  module)

(define* (create-module-interface module exports #:optional name)
  (let ((i (make-module)))
    (set-module-name! i (or name (list (gensym))))
    (set-module-kind! i 'custom-interface)
    (for-each 
     (lambda (import)
       (if (pair? import)
	   (module-add! i (cadr import) (module-variable module (car import)))
	   (module-add! i import (module-variable module import))))
     exports)
    i))

(define* (create-library-interface lib exports #:optional name)
  (let* ((name (or name (list (gensym))))
	 (l (make-r6rs-library name)))
    (set-r6rs-library-interface! 
     l (create-module-interface (r6rs-library-interface lib) exports name))
    (set-r6rs-library-exports! 
     l (map (lambda (x) (if (pair? x) (cadr x) x)) exports))
    (set-r6rs-library-parent! l lib)
    l))

(define (instantiate-library lib-expr)
  (define name (library-name lib-expr))
  (define imports (library-imports lib-expr))
  (define exports 
    (fold (lambda (x lst) (append lst (if (pair? x) (cdr x) (list x))))
	  '()
	  (library-exports lib-expr)))

  (define library (make-r6rs-library (library-name lib-expr)))
  (define module (create-empty-module))

  (define (binding-name binding) (if (list? binding) (car binding) binding))

  (define local-definitions (list 'exports))

  (define phase-library-cache (make-hash-table))
  (define (inject-bindings-for-phase! m phase)
    (and=> (hashv-ref phase-library-cache phase)
	   (lambda (ifaces) (for-each (lambda (i) (module-use! m i))
				      (map r6rs-library-interface ifaces)))))

  (define (expand expr m p)
    (if (pair? expr)
	(let ((ce (car expr)))
	  (cond ((eq? ce 'define) 
		 (eval (cons* ce (cadr expr) (expand (cddr expr) m p)) m))
		((eq? ce 'define-syntax)
		 (let ((m+ (create-empty-module))
		       (p (+ p 1)))
		   (inject-bindings-for-phase! m+ p)
		   (let ((rhs (eval (expand (caddr expr) m+ p) m+)))
		     (let ((e `(define-syntax ,(cadr expr) ,rhs)))
		       (eval e m)))))
		(else (map (lambda (x) (expand x m p)) expr))))
	expr))
    
  (define (hashv-append! h k v)
    (or (and=> (hashv-ref h k) (lambda (ov) (hashv-set! h k (append ov `(,v)))))
	(hashv-set! h k `(,v))))

  (for-each 
   (lambda (import) 
     (let* ((import-set (if (eq? (car import) 'for) (cadr import) import))
	    (interface (import-library import-set)))
       (if (equal? (r6rs-library-name interface) '(rnrs (6)))
	   (begin (hashv-append! phase-library-cache 0 interface)
		  (hashv-append! phase-library-cache 1 interface)))
       (if (eq? (car import) 'for)
	   (for-each
	    (lambda (phase)
	      (cond ((eq? phase 'run)
		     (hashv-append! phase-library-cache 0 interface))
		    ((eq? phase 'expand)
		     (hashv-append! phase-library-cache 1 interface))
		    ((and (list? phase) (eq? (car phase 'meta)))
		     (hashv-append! phase-library-cache (cadr phase) interface))
		    (else (error "Invalid import level specification"))))
	    (cddr import))
	   (hashv-append! phase-library-cache 0 interface))))
   imports)

  (inject-bindings-for-phase! module 0)
  (for-each (lambda (expr)
	      (if (and (list? expr) (memq (car expr) '(define define-syntax)))
		  (begin (expand expr module 0)
			 (append! local-definitions 
				  (list (binding-name (cadr expr)))))
		  (eval expr module)))
	    (library-body lib-expr))

  (let ((locals (cdr local-definitions)))
    (receive 
      (export-vars export-names)
      (let f ((vars (list)) (names (list)) (lst exports))
	(cond ((null? lst) (values vars names))
	      ((pair? (car lst))
	       (f (cons (caar lst) vars) (cons (cadar lst) names) (cdr lst)))
	      (else (f (cons (car lst) vars)
		       (cons (car lst) names)
		       (cdr lst)))))
      (if (not (null? locals))
	  (module-export! module locals))
      (module-re-export! module (lset-difference eq? export-vars locals))
      (let ((module-interface (create-module-interface module exports name)))
	(set-module-public-interface! module module-interface)
	(set-r6rs-library-module! library module)
	(set-r6rs-library-interface! library module-interface)
	(set-r6rs-library-exports! library export-names))))
  (hash-set! interface-registry name library))

(define (version-matches? version-ref target)
  (define (sub-versions-match? v-refs t)
    (define (sub-version-matches? v-ref t)
      (define (curried-sub-version-matches? v) (sub-version-matches? v t))
      (cond ((number? v-ref) (eqv? v-ref t))
	    ((list? v-ref)
	     (let ((cv (car v-ref)))
	       (cond ((eq? cv '>=) (>= t (cadr v-ref)))
		     ((eq? cv '<=) (<= t (cadr v-ref)))
		     ((eq? cv 'and) 
		      (every curried-sub-version-matches? (cdr v-ref)))
		     ((eq? cv 'or)
		      (any curried-sub-version-matches? (cdr v-ref)))
		     ((eq? cv 'not) (not (sub-version-matches? (cadr v-ref) t)))
		     (else (error "Incompatible sub-version reference" cv)))))
	    (else (error "Incompatible sub-version reference" v-ref))))
    (or (null? v-refs)
	(and (not (null? t))
	     (sub-version-matches? (car v-refs) (car t))
	     (sub-versions-match? (cdr v-refs) (cdr t)))))
  (define (curried-version-matches? v) (version-matches? v target))
  (or (null? version-ref)
      (let ((cv (car version-ref)))
	(cond ((eq? cv 'and) (every curried-version-matches? (cdr version-ref)))
	      ((eq? cv 'or) (any curried-version-matches? (cdr version-ref)))
	      ((eq? cv 'not) (not version-matches? (cadr version-ref) target))
	      (else (sub-versions-match? version-ref target))))))

(define (import-library import-spec)
  (define (wrap-guile-module module)
    (let ((li (make-r6rs-library (module-name module))))
      (set-r6rs-library-module! li module)
      (set-r6rs-library-interface! li module)
      (set-r6rs-library-exports! 
       li (hash-map->list (lambda (x y) x) (module-obarray module)))
      li))

  (define (locate-library library-reference)
    (receive
      (name version)
      (partition symbol? library-reference)
      (let ((interface (false-if-exception (resolve-interface name))))
	(or (hash-ref interface-registry library-reference)
	    (and-let* ((version-table (hash-ref library-registry name))
		       (cversion (if (null? version) version (car version))))
	      (or (and=> (assoc cversion version-table version-matches?)
			 (lambda (x) (instantiate-library (cdr x))))
		  (error "No version of library found to match version-ref"
			 name
			 cversion
			 version-table)))
            (and interface (hash-set! interface-registry 
				      library-reference 
				      (wrap-guile-module interface)))
	    (error "Unable to resolve interface for library" 
		   library-reference)))))

  (define (resolve-library-interface import)
    (let ((ci (car import)))
      (cond 
       ((eq? ci 'library) (locate-library (cadr import)))
       ((or (eq? ci 'only) (eq? ci 'rename))
	(create-library-interface (resolve-library-interface (cadr import))
				  (cddr import)))
       ((eq? ci 'except) 
	(let ((i (resolve-library-interface (cadr import))))
	  (create-library-interface 
	   i (lset-difference eq? (r6rs-library-exports i) (cddr import)))))
       ((eq? ci 'prefix)
	(let* ((i (resolve-library-interface (cadr import)))
	       (prefix-str (symbol->string (caddr import))))
	  (create-library-interface
	   i (map (lambda (x) 
		    (cons x (list (string->symbol 
				   (string-append prefix-str 
						  (symbol->string x))))))
		  (r6rs-library-exports i)))))
       (else (locate-library import)))))
  (resolve-library-interface import-spec))

(define (import import-spec)
  (let ((lib (import-library import-spec)))
    (or lib (error "Unable to import library for import spec " import-spec))
    (module-use! (current-module) (r6rs-library-interface lib))))

(define (register-library library-expr)
  (define (version-less? x y)
    (cond ((null? x) #f)
	  ((null? y) #t)
	  (else (let ((cx (car x))
		      (cy (car y)))
		  (cond ((< cx cy) #t)
			((> cx cy) #f)
			(else (version-less? (cdr x) (cdr y))))))))
  (receive 
    (name version)
    (partition symbol? (library-name library-expr))
    (let ((cversion (if (null? version) version (car version))))
      (or (and=> (hash-ref library-registry name)
		 (lambda (version-table)
		   (merge! version-table 
			   `(,(cons cversion library-expr))
			   version-less?)))
	  (hash-set! library-registry name `(,(cons cversion library-expr)))))))

(define (register-from-path filename)
  (define (quoting-read port)
    (let ((library-expr (read port)))
      (if (eof-object? library-expr)
	  library-expr
	  (begin (register-library library-expr) *unspecified*))))
  (with-fluids ((current-reader quoting-read)) (load-from-path filename)))

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

end of thread, other threads:[~2009-03-22 22:30 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-02-06 15:55 R6RS Libraries Ludovic Courtès
     [not found] <2bc5f8210812271705h3f57cb29w5bb83cb02abe971@mail.gmail.com>
     [not found] ` <m3k59ktv2g.fsf@pobox.com>
     [not found]   ` <2bc5f8210812282238p1f91f352id7eca5280dc9ff6a@mail.gmail.com>
     [not found]     ` <2bc5f8210901012010g2ebb6effx5c966d0e26fe382b@mail.gmail.com>
     [not found]       ` <8763kt48zi.fsf@gnu.org>
     [not found]         ` <m3iqosrcn7.fsf@pobox.com>
     [not found]           ` <2bc5f8210901111521i1a5ec85em65ee20135cc55ebb@mail.gmail.com>
     [not found]             ` <877i4z89jy.fsf@gnu.org>
2009-01-26  0:27               ` r6rs libraries Julian Graham
2009-01-27 10:51                 ` Andy Wingo
2009-01-27 20:09                   ` Ludovic Courtès
2009-01-28 17:26                   ` Julian Graham
2009-02-16 18:35                     ` Julian Graham
2009-02-16 20:58                       ` Andreas Rottmann
2009-02-18  6:08                         ` Julian Graham
2009-02-18 14:27                           ` Andreas Rottmann
2009-02-17 21:43                       ` Ludovic Courtès
2009-02-18  5:37                         ` Julian Graham
2009-02-18  8:53                           ` Ludovic Courtès
2009-02-18 21:16                             ` Andy Wingo
2009-03-04  5:23                       ` Julian Graham
2009-03-04  8:39                         ` Ludovic Courtès
2009-03-04 22:51                           ` Julian Graham
2009-03-06 23:39                             ` Ludovic Courtès
2009-03-07  0:43                               ` Julian Graham
2009-03-22 22:30                                 ` Julian Graham

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