Closed kdsch closed 4 years ago
Here’s one way to do it, putting each set of format-specific tag functions in its own source file, and then stitching everything together with a couple macros.
Here’s another way, using classes and inheritance.
Some have suggested that units are a possibility, but I don’t recall seeing a working example.
Thanks @mbutterick!
For what it’s worth, some time ago I looked into using units for this purpose. The problems I bumped into were
At the time I couldn’t determine how to conditionally call define-values/invoke-unit/infer
since it is a top-level form [edit: maybe rather, module level?]. With a better understanding of macros, this may not be an obstacle anymore.
More crucially, it doesn’t appear that (current-poly-target)
will return anything but 'html
at expansion time.
@otherjoel Good to know.
I tried using units today. I found that define-values/invoke-unit/infer
expects identifiers, which implies converting symbols (targets) into identifiers. This conversion would have to happen at run time, as the target varies at run time. I'm guessing this is a contradiction; I don't think identifiers can be created at run time. Whereas, macros can create them at compile time.
Recalling the notion of message passing I encountered in SICP, I experimented with that approach.
(define (target)
(case (current-poly-target)
[(html) html-target]
[(txt) txt-target]
[else (error "unknown target:"
(current-poly-target))]))
(define (heading . args) ((target) 'heading args))
(define (emph . args) ((target) 'emph args))
(define (html-target method . args)
(define (heading . elements)
(txexpr 'h1 empty elements))
(define (emph . elements)
(txexpr 'strong empty elements))
(case method
[(heading) (heading args)]
[(emph) (emph args)]
[else (error "unknown method:" method)]))
This seems to have taken me a bit farther, but I'm now violating contracts in txexpr
. Seems like a basic error, but I'm not sure what's going on, as the implementation didn't do this before.
txexpr: contract violation
expected: txexpr-elements?
given: '((("Karl Schultheisz")))
where resume.poly.pm
contains
#lang pollen
◊heading{Karl Schultheisz}
Today is ◊(get-date). I ◊emph{mostly} want this job.
The problem was too many variadic functions. After fixing that, the message-passing style more or less does what I want.
I'm learning Pollen to ditch Hugo and every static site generator that frustrates me. I am somewhat familiar with Scheme, but a newcomer to Racket, especially the module system.
I've done the fourth tutorial, on multiple output targets. I understand that
pollen.rkt
defines a module that resolves Pollen tags. The tutorial uses branching expressions within tag functions to implement different targets.I want to make the implementation choice at the module level rather than in the tag functions. In other words: separate targets into different components. I think of a Pollen document as requiring an interface, with the current poly target controlling which implementation is used. However, I'm not skilled enough in Racket to do this.