Code: Inform 7 for the rest of us

Inform 7 has historically been less than accessible to programmers of traditional programming languages. For instance, suppose one were using the Sieve of Eratosthenes to find primes, as one does. Idiomatic Inform 7 might go something like:

The limit is initially 100.

Divides exactly relates a number to various numbers.
The verb to factor means the divides exactly relation.

Definition: a number is known to be a product rather than known to be prime
  if a number relates to it by the divides exactly relation.

To exclude multiples of (n - a number):
        let i be n * n;
        while i <= limit:
                now i is factored by n;
                now i is i + n;

when play begins:
        repeat with i running from 2 to the square root of limit:
                unless i is known to be a product, exclude multiples of i;
        repeat with i running from 2 to limit:
                if i is known to be prime, say "[i] ";

But with my new extension Code, that becomes simply:

Include Code by Zed Lopez.

main:
  var h = map number => truth state;
  var limit = 100;
  repeat for p in 2 to sqrt limit begin;
    unless (h => p || false) begin;
      var i = p ** 2;
      while (i <= limit) begin;
        h => i = false;
        i += p;
      end while;
    end unless;
  end repeat;
  repeat for j in 2 to limit begin;
    if (h => j || true), print "[j] ";
  end repeat;

Now that looks like a proper program. As you see, = can be used for assignment, and arithmetic assignment operators like += are defined. Hashes are provided by Data Structures by Dannii Willis and called “maps”. Local variables can be declared with var. But Code has so much more. Want to find the number of days in a month of a given year?

To decide what number is days in month (m - a number) of (y - a number):
  if switch m begin;
    if in { 4, 6, 9, 11 }, return 30;
    if == 2, return (y % 4 > 0 or (y % 100 == 0 and y % 400 > 0)) ? 28 # 29;
    if default case, return 31;
  end if;

This demonstrates Code’s switch statement and ternary operator. Or suppose you’d been having your game write a log file and now wanted to get a counts of individual words in it, as one also does. Code makes it easy!

The file of log is called "log".

main:
  var file = file of log;
  var h = map text => number;
  open file for <f;
  repeat for line in lines of read file begin;
    while line =~ / "(\w+)" /g begin;
      h => $1 = (h => $1 || 0) + 1;
    end while;
  end repeat;
  number var v;
  repeat for k in sorted (keys h) begin;
    v = h => k;
    puts "[k] [v]";
  end repeat;

Yes, that’s Perl-style regexp syntax, and you can loop over a regexp with /g. And this just scratches the surface of what Code has to offer.

Inform 7’s massive walls of text don’t have to be a barrier to entry anymore!

Installation notes

If you want to take these for a spin yourself (and who could resist?) there are a bunch of dependencies. Probably easiest to install the whole Friends repo, but individually of my extensions you would need:

Bit Ops version 1
Char version 1
Code version 1
Custom Banner and Version version 1/220306
If True version 1/211209
List Utilities version 1/220327
Strange Loopiness version 1/220222
Switch version 2/220401
Text Loops version 1/211225
Textile version 1/220401

and two by Dannii:

Alternative Startup Rules version 1/140516
Data Structures version 1/220331

But as discussed in the Data Structures thread, Data structures further requires creating an I6T directory under your project’s materials directory, and putting his modified Figures and Load-Figures.i6t there.

18 Likes

This is hilarious!

2 Likes

If the Syntax.preform part of the Inform system ever gets fully built out, it could be used to enable this sort of thing.

I think this is real and the perfect April Fool’s joke at the same time. I enjoyed it on that basis anyway :+1:

5 Likes
if switch m begin;
    if in { 4, 6, 9, 11 }, return 30;
    if == 2, return (y % 4 > 0 or (y % 100 == 0 and y % 400 > 0)) ? 28 # 29;
    if default case, return 31;
  end if;

You can probably remove the ifs from these lines and put cases instead.

Also note that Maps are not hashes. Using them heavily will result in poor performance. (But if we can finish better flex then we could improve that a lot.)

1 Like

The example doesn’t show it, but one can use a code block as a case, something I really wanted to allow:

 if == 2 begin;
  if (y % 4 > 0 or (y % 100 == 0 and y % 400 > 0)), return 28;
  return 29;
end if;

I didn’t see a better way to offer both a one-line and code block choice. It’s not the syntax I’d choose with complete freedom of choice… but I was pleased with it under the circumstances.

I started testing my word count example with 5 paragraphs of Lorem Ipsum. It was so painfully slow, I cut it down to two. And that still took a couple seconds.

I meant that the lines could begin with case. Just to make it even more traditional.

Oh no. Yeah any map with lots of keys is going to be pretty gross. It can be improved, just will take time.