The way I have found to do this is to both use the `tag` form and
explicitly rename all signature elements, e.g.:

(define-unit twice-collector@
  (import (tag base (prefix base: collector^)))
  (export collector^)

  (define item/c base:item/c)
  (define (collect . xs)
    (apply base:collect (append xs xs))))

However, I also find this unsatisfying, and I would note that there is a
bug that prevents doing this sort of thing with `define-unit/contract`:
https://github.com/racket/racket/issues/2196

-Philip


On Wed, Oct 17, 2018 at 11:29 AM Alexis King <lexi.lam...@gmail.com> wrote:

> Imagine I have the following signature:
>
>     (define-signature collector^
>       [(contracted
>         [item/c contract?]
>         [collect (-> item/c ... item/c)])])
>
> Writing a unit that exports this signature is easy. For example, here’s
> one that sums its arguments:
>
>     (define-unit sum-collector@
>       (import)
>       (export collector^)
>
>       (define item/c number?)
>
>       (define (collect . xs)
>         (apply + xs)))
>
> But imagine I want to instead write a higher-order unit that implements
> collector^ by wrapping an existing collector^ implementation. For example,
> I could write a unit that applies the “base” collector to a doubled list:
>
>     (define-unit twice-collector@
>       (import (rename collector^ [base:collect collect]))
>       (export collector^)
>
>       (define (collect . xs)
>         (apply base:collect (append xs xs))))
>
> However, this fails with the following error message:
>
>     define-unit: import item/c is exported
>
> The error message is not wrong — item/c is indeed re-exported by
> twice-collector@, but this is because twice-collector@ doesn’t care about
> item/c, only collect. However, I can accept that this program is rejected,
> since it isn’t clear how to link twice-collector@ with a base collector;
> there would be two different units that export collector^ in a single
> compound unit. Therefore, it seems that the intended solution would be to
> tag the import:
>
>     (define-unit twice-collector@
>       (import (tag base (rename collector^ [base:collect collect])))
>       (export collector^)
>
>       (define (collect . xs)
>         (apply base:collect (append xs xs))))
>
> However, this program is still rejected with the same error message. In
> this case, I can’t understand why.
>
> One alternative is to avoid using the import mechanism altogether and
> instead define twice-collector@ as a function, creating a sort of “unit
> mixin”:
>
>     (define (twice-collector@ base-collector@)
>       (unit
>         (import)
>         (export collector^)
>
>         (define-values/invoke-unit base-collector@
>           (import)
>           (export (rename collector^ [base:collect collect])))
>
>         (define (collect . xs)
>           (apply base:collect (append xs xs)))))
>
> This works, but it seems a little bit silly, since it effectively performs
> the linking manually and runs around the linker.
>
> What is the “correct” way to write higher-order units? I looked for ideas
> in the original units paper (Units: Cool Modules for HOT Languages), and it
> seems to just use the function approach I mentioned above, but the system
> it describes is meaningfully different from the one implemented in Racket,
> and I can’t find very much information about the design of the Racket
> system.
>
> Alexis
>
> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to racket-users+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to