Feb 05 2011
Not smart enough
The sufficiently smart compiler is one that removes any need for engineering judgement/ability on the part of the programmer. The sufficiently aesthetic compiler does the same for artistic judgement.
Comments Off
Feb 05 2011
The sufficiently smart compiler is one that removes any need for engineering judgement/ability on the part of the programmer. The sufficiently aesthetic compiler does the same for artistic judgement.
Comments Off
Feb 04 2011
My troubles with parsing the ComicBake script format have been resolved, in particular by checking out John Goerzen’s ConfigFile package, which uses the same parser combinators to read INI files.
The code in ScriptParser.hs is slightly reduced and hopefully more robust and flexible than it was before. It certainly now recognises optional (Thinking) keyword, though right now the option is ignored later in the compilation process.
One advantage of finalising the parser is that I have a much better idea what the file format is. It helped to crystallise some of the fuzzy areas in my mind. This is the inevitable result of any programming endeavour — vague ideas are made exact or abandoned altogether.
I’ve updated the README to describe the key/value format used for defining metadata, and ensured that the old comics all still build properly. The new parser just skips comments which were previously meaningful if they don’t have the correct keyword specified. So I didn’t need to rewrite my examples.
Also I just noticed that I’ve made 150 commits to this repository. I doubt that means anything but I’m surprised it’s so many. I suppose at one point I was being quite good about lots of little commits for independent changes. Lately I’ve just been working on hulking great code bombs which can’t be split up until after they’re done, and by then it hardly seems worth it.
Comments Off
Feb 03 2011
Thinking about calculating the number of working days between two dates. (Note, I haven’t actually executed any of this code, just thought about it. It could be quite wrong.)
For this scenario I assume that end is no earlier than start. (Obviously we can deal with this situation using some wrapper function to sort the dates if the result depends on this order.)
If start and end are the same day we define this as “zero working days”.
workingdays :: Day -> Day -> Integer workingdays start end | start == end = 0 | otherwise = undefined
If start and end are both the same day of the week then there will be a whole number of “working weeks” between the dates, eg one Monday to the next Monday is one working week. A working week is 5 days, so the number of working days is the number of working weeks times five.
We determine if two dates occur on the same day of the week by checking the number of days between them. Any number which is a multiple of seven (0, 7, 14, 21, …) indicates the two dates are a whole number of weeks apart. Multiples of seven produce a remainder of zero when divided by seven, so we divide the span by seven and check the remainder.
workingdays :: Day -> Day -> Integer workingdays start end | start == end = 0 | is_sameday = 5 * wholeweeks | otherwise = undefined where is_sameday = diffDays start end `mod` 7 == 0 wholeweeks = diffDays start end `div` 7
At this point we notice that the first scenario is a simplified case of the second, where the two dates occur on the same day of the week with exactly no weeks between them. We can just collapse them into one calculation.
workingdays :: Day -> Day -> Integer workingdays start end | is_sameday = 5 * wholeweeks | otherwise = undefined where is_sameday = diffDays start end `mod` 7 == 0 wholeweeks = diffDays start end `div` 7
If the two dates don’t fall on the same day there may be some fraction of a working week between the two. The number of days leftover in the last week is the remainder when the number of weeks is calculated, which we’ve already worked out once. Rather than doing it twice we’ll separate it out into whole weeks and days.
workingdays :: Day -> Day -> Integer workingdays start end | days == 0 = 5 * weeks | otherwise = 5 * weeks + partweek where (weeks,days) = diffDays start end `divMod` 7 partweek = undefined
The bit we don’t know yet is the number of working days which make up the last part-week. The value of partweek is between zero and days with an upper limit of 5 because there can only be 5 working days between any two dates less than a week apart. At this point we’d be as well to just count them.
workingdays :: Day -> Day -> Integer workingdays start end | days == 0 = 5 * weeks | otherwise = 5 * weeks + partweek where (weeks,days) = diffDays start end `divMod` 7 partweek = length $ filter weekday $ enumFromTo newstart end newstart = addDays (7 * weeks + 1) start
We count the number of weekdays from the day after the first day, since that day doesn’t count. At this point it probably hasn’t escaped you that we’ve got more repetition. We could remove the first case (for whole weeks) because partweek will evaluate to zero in that case.
If there is a nicer way to calculate the remaining part of the week I haven’t spotted it. I feel sure there must be something better than just looping over the remaining days, though maybe I am wrong.
Comments Off
Feb 02 2011
In the last few days I’ve been snatching some moments to rewrite the awful, ugly parser in ComicBake into something readable and adaptable. While doing this I’ve been slowly rewriting the format of the accepted scripts. All of the improvements have been fairly subtle but sometimes with large improvements in usability and ease of implementation.
The big one is the comments. Previously the first N comments were hard-coded to contain the comic title, author and other information, prefixed with the “comment delimiter”, a double-dash symbol. I’ve adopted a key-value style instead which means comments can be included (or omitted) as necessary from the header without problem:
Old style:
-- Pandemic -- Board games -- Dougal Stanton -- January 2011
New style:
-- title: Pandemic -- series: Board games -- author: Dougal Stanton -- date: January 2011
At the moment I’m only storing the title and author names but it’s possible to tag anything now and use it later if necessary. The tags can be re-ordered as desired and if you miss them altogether I just use an empty string.
I’m also experimenting with adding directions to indicate speech/thought bubbles. At the moment the code uses this format but it may change:
Garfield: (Thinking)
I hate Mondays
Sadly I’ve realised that the language is still ambiguous about divisions between scenes. A scene may end when a new one starts, or when the file ends. Getting it to manage both is proving awkward. I don’t want to add more syntactic elements just to make it easier to parse, so I’ll have to see how other languages which define loosely-grouped sections (eg, INI files) are parsed.