Aug. 9th, 2013

jducoeur: (Default)
Okay, here's a very offbeat question looking for opinions. I'm committing the dangerous (but probably to-be-common) act of crossing the streams between SCA and Querki here.

One of my long-term projects is running the Medieval and Renaissance Games Homepage. I've run this page for many years now (since the late 90s, when I got seriously into period games), and I consider it an important public resource -- it's my agglomeration of all useful-looking links I know of on the topic. But frankly, it's gotten pretty long in the tooth -- it's still written in hand-maintained HTML, and is kind of a pain in the ass at this point. (With the result that it has been *years* since I last updated it.)

There is, of course, an obvious solution: this is a *great* candidate for a Querki Space. After all, Querki is all about "semi-structured" data, and this site is about as "semi-structured" as you can get -- a mix of miscellaneous webpages with what amounts to a database of links and reconstructions of many sorts. And with Querki's planned collaboration features, I'll be able to open this solo project up to other members of the period games community, so we can build the one true wiki on the subject. So I think it's clear that I'm going to move the Period Games Homepage to Querki, likely within the next month or two.

That said, it does force me to think about what the schema should look like, which introduces an interesting question: how should I describe the family tree of period games? Calling it a "family tree" is clearly correct -- you can see the hierarchy visibly in the existing Rules page -- and I'm finding myself whimsically thinking about following the Linnaean taxonomy, grouping things more or less like this:
  • Phylum: the broad kind of game -- eg, Active, Board, Card, Dice

  • Family (or maybe Genus): what we think of as a single game today, but usually were a collection of linked variants -- eg, Chess, Tables, Tafl

  • Species: a single precise variant in a Family -- eg, Shatranj, Courier Chess, Dice Chess, Chess of the Mad Queen

  • Morph: a specific reconstruction of a Species -- eg, the various Hnefatafl reconstructions
Admittedly, this is probably more clever than useful. But I am struck at the way the memetic evolution of games, and the resulting family tree, *feels* like a biological evolutionary tree. (And purely on the Querki side, now I'm beginning to ponder whether there is anything that should be reified into Querki's type system to support such trees, since there are a lot of use cases for them.)

Anyway, looking for any thoughts and opinions about what the schema should look like here. I have a rapidly growing collection of links that I need to record somewhere, so I may as well start this project of converting the Homepage to Querki sometime soon...
jducoeur: (querki)
Okay, time for a little burble. [This one is solely for the truly geeky programmers; the context is, of course, Querki. I don't have anyone to do code reviews with, so I'm afraid you get the burbles.]

So two days ago, I implemented _modTime, which produces the time that the received Thing was last changed. Yesterday, I realized that this was really only useful if you can sort on it, so I enhanced _sort to take a parameter, like this:
[[Page._instances -> _sort(_modTime)]]
But of course, that produces the page in time order, which is almost never what you want -- 9 times out of 10, you want to print things in *reverse* time order, from newest to oldest.

So I clearly wanted some sort of "_desc" modifier on _sort, so that you can tell it to sort in descending order. My first instinct was to just add a _reverse function, an easy and just plain useful tool to just reverse the list order, but that's not quite right: I want the results to be in descending order by time, but ascending order by name if the times match. I specifically want to reverse _modTime, *not* necessarily the entire results.

Thinking about it a little, I decided that the obvious syntax had to be:
[[Page._instances -> _sort(_desc(_modTime))]]
That is, "sort by _modTime, descending".

But wait a second -- what does that *mean*? I mean, _modTime is being applied to each element in the list; saying that an *element* is "descending" seemed almost meaningless, until I thought about it a bit more, and realized that what I'm doing is transforming the *type* of the result -- "_desc(_modTime)" clearly means "return each item's modTime, with the sort order of the returned type reversed".

That's kind of insane. And I was completely floored to discover that this is, pretty much, all the code it required (going into Scala now, and omitting documentation):
class DescendingType[VT](baseType: PType[VT]) extends DelegatingType[VT](baseType) {
  override def doComp(context:ContextBase)(left:VT, right:VT):Boolean = !realType.doComp(context)(left, right)
}

object DescMethod extends InternalMethod(DescMethodOID, toProps(setName("_desc")))
{
  override def qlApply(context:ContextBase, paramsOpt:Option[Seq[QLPhrase]] = None):QValue = {
    paramsOpt match {
      case Some(params) => {
        val innerRes = context.parser.get.processPhrase(params(0).ops, context).value;
        innerRes.cType.makePropValue(innerRes.cv, new DescendingType(innerRes.pType))
      }
      case None => WarningValue("_desc is meaningless without a parameter")
    }
  }
}
That is, when you call "_desc", it processes its own parameter (params(0).ops), passing in the received context; rewrites the result using the same Collection (innerRes.cType), and wrapping the Type (innerRes.pType) in a pseudo-Type (DescendingType) that reverses the result of comparisons (doComp()); and passes that down the pipeline.

It simply works, and took less than half an hour to come up with. Wow. Yes, I understand that the above looks kinda cryptic, but seriously: I can't think of any other language I've ever played with that could do this, preserve type safety, and not have me tied in knots for a day or two.

(And the implications here are staggering. I'd added DelegatingType for a fairly minor boot-time requirement last month, and hadn't given it much thought. But if this works, it means that Querki can do almost arbitrary type transformations at runtime internally. Which means that sooner or later, we're going to be getting the same sorts of high-level Type operations in QL itself. Neat...)

Profile

jducoeur: (Default)
jducoeur

May 2025

S M T W T F S
    123
45678910
11121314 151617
18192021222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags