I run into this problem a lot whenever I'm generating some text. I'll be making 
what amounts to a sequence of strings being appended, and do something like 
this:

(apply string-append 
  (list "<p><a href=\"" somewhere "\">" something "</a></p>"))

Compared to un-parsing a representation of a document tree every single time, 
simplifying document production down to a bunch of string concatenations is 
pretty efficient. The problem happens when I introduce conditionals, like this:

(list
  "<p id=\"navigation\">"
  (if prev
    (list "<a href=\"" prev "\">Prev</a>")
    '())
  (if next
    (list "<a href=\"" next "\">Next</a>")
    '())
  "</p>")

Now I no longer have a sequence of strings, but instead a nested list of 
strings. Then I usually call (apply string-append (flatten list-of-strings)) 
and don't worry about it, but it'd be even cooler if I could proactively 
flatten it.

(if prev
  (if next
    (list 
      "<p id=\"navigation\">"
      "<a href=\"" prev "\">Prev</a>"
      "<a href=\"" next "\">next</a>"
      "</p>")
        (list 
      "<p id=\"navigation\">"
      "<a href=\"" prev "\">Prev</a>"
      "</p>"))
  (if next
          (list 
      "<p id=\"navigation\">"
      "<a href=\"" next "\">next</a>"
      "</p>")
          (list 
      "<p id=\"navigation\">"
      "</p>")))

Obviously that's horrible code, since I don't want to type the surrounding 
stuff for every possible logic pathway in my code. But it'd be relatively 
simple to concatenate whatever the result is! I guess what I'm asking is how 
would I take code like this:

(list 
  "<p id=\"navigation\">"
  (splicing-if prev
    (splicing-list "<a href=\"" prev "\">Prev</a>")
    nada)
  (splicing-if next
    (splicing-list "<a href=\"" next "\">Next</a>")
    nada)
  "</p>")

...and have the result inherently be a flat list of strings? Not a complex tree 
that I then have to walk with (flatten), but genuinely just a list of strings?

Something with (reset) and (shift) maybe? Something with (and-let)? To make 
this happen, would I have to instrument the conditionals like (if)? Would I 
have to instrument the (list) forms that they result in?

Obviously if my conditionals produce simple strings it's easy:

(list 
  "things: "
  (if thing1
    thing1
    "")
  (if (and thing1 thing2)
     " and "
     "")
  (if thing2
    thing2
    ""))

Even that is kind of cludgy though, because the "" fallthrough results in lists 
like (list "things: " thing1 "" "") instead of the ideal: (list "things: " 
thing1)

One possible solution is to use mutable variables and shared state. (ugh)

(write "<p id=\"navigation\">")
(when prev
    (write "<a href=\"")
    (write prev)
    (write "\">Prev</a>"))
(when next
    (write "<a href=\"")
    (write next)
    (write "\">Next</a>"))
(write "</p>")

Another thing I've tried is concatenations of concatenations:

(apply string-append 
  "<p id=\"navigation\">"
  (if prev
    (string-append "<a href=\"" prev "\">Prev</a>")
    "")
  (if next
    (string-append "<a href=\"" next "\">Next</a>")
    "")
  "</p>")

That of course scatters fallthrough "" strings in the calculation, and since it 
calls string-append multiple times, the implementation can't exactly allocate 
the result all at once, and must spend more time fooling around with memory. 
Creating strings, only to destroy them as soon as they've been appended to the 
larger string.

But there's no way I've ever been able to figure to produce generated text that 
is just a flat list of strings, if I ever want to have conditional decisions 
about what to go in that list.

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