Thinking about punctuation

One of the unique advantages of Inform 7 over other programming languages is that you can often read it out loud. It’s nice to have a language with less punctuation, even if it is more verbose sometimes.

Thinking about this made me realize what a problem the IDE’s handling of tabs is - it goes against the read-out-loud-ability of Inform in a very frustrating way. Of course tables are the worst problem, but then they’re a fundamentally not-out-loud-readable sort of thing. But conditional code can be written in English, sometimes in a not-ambiguous way. It would be an interesting challenge, possibly for I7 or possibly for another language, to come up with a syntax for if-then-else (and maybe even looping) that did not require punctuation or whitespace at all (although as a visual aid, automatic indentation would be nice, and possible if there were no ambiguitites).

So Inform has a more English-like “otherwise” rather than “else.” But that’s mostly cosmetic. What we would really need is a way to distinguish:

if A: if B: do C: else: do D:

from:

if A: if B: do C: else: do D:

I guess behind the scenes we have “begin” and “end if,” but they seem so un-Inform like that I’ve never wanted to use them. Other languages have “then,” which seems much more English-like than “begin” but I guess it doesn’t work for loops.

Then again, there’s no reason not to have a different word to use with loops than with conditions - in fact that might make the language even more “natural.”

Just brainstorming here…

if the parlor is open: check if the liquor cabinet is locked: If so, unlock the liquor cabinet. If not, get a drink. otherwise: open the parlor.

if Superman is flying: check if Superman carries Lois (this is the Lois-is-flying condition): if so, check if Lois is frightened: if so, Lois screams. if the Lois-is-flying condition is not so: Superman calls Lois.

A “named condition” could be like an embedded “To decide” phrase, usable in more places… or its result could simply be stored as a named temporary variable as opposed to the anonymous temporary variables referred to by “if so” and “if not”

Another sort of named condition, although more subtly so…

if Superman is flying: check first if Superman carries Lois: if the first is so, check second if Lois is frightened: if the second is so, Lois screams. if the first is not so: Superman calls Lois.

Some alternate phrasings for “end if”…

if Superman is flying: check if Superman carries Lois: if so, check if Lois is frightened: if so, Lois screams. done checking; if not: Superman calls Lois. No more conditions.

“check that” could be used when there will be no “else”:

if Superman is flying: check if Superman carries Lois: check that Lois is frightened: if confirmed, Lois screams. if not: Superman calls Lois.
Perhaps confusing when read aloud, but at least not ambiguous. And the auto-indent could sort it out if you can look at it.

Another wording for a “no-else” condition, though this might be confused with an every turn rule:

As long as Lois is frightened: Lois screams.

Here’s another “end if,” used to demonstrate the termination of multiple statements…

            if so, Lois screams.
            if not:
                Lois sings.
                Superman flies higher.
                Do no more.

Or statements could always be single by default, with a keyword to indicate continuation…

            if so, Lois screams.
            if not:
                Lois sings.
                Also, Superman flies higher.

Never mind that “check” is already a keyword, I’m just brainstorming. Any ideas?

I’m on a roll! Let’s try…

Repeat with the garment running through every wearable thing: Now the garment is worn. Increment the warmth of the player. Do the next garment. [or just "next", a perfectly good word from Perl]

Your loop already is re-writable. Now every wearable thing is worn; Increment the warmth of the player by the number of worn things;
But I’d like to use “each” to implicitly imply a loop. now every worn thing is tattered; now the #/rips in each worn thing is a random number from 1 to 3; try patching up each worn thing;
…which would compile as … repeat with X running through every worn thing: now X is tattered; now the #/rips in X is a random number from 1 to 3; try patching up X;
As-is, Inform would make three separate loops, one for each line, rather than combining them into a single loop with a three-line body.

I dunno. This kind of stuff is an old problem. For complicated, nested if-statements, I think natural language would prefer an approach of asserting rules, rather than the imperative outline we usually program with. For example, to take your modified example if Superman is flying: animate cape whipping in wind; check if Superman carries Lois: check that Lois is frightened: if confirmed, Lois screams. if not: Superman calls Lois.
It might be written as Lois screams when Lois is frightened and Superman carries her while flying. Superman calls Lois when he is not flying and not carrying her.
…although the if-statements can still carry extra information, in that no matter how the conditions go, the ordering of the results are the same. With the assertive approach, a line to assert which effect happens first would be needed. Animate cape whipping in wind when Superman is flying, but before doing anything with Lois.

Brainstorming is fun and easy.

Maybe it was a bad example?

Another case where I would want a named condition or remembered condition (or description):

With every worn thing: now each one is tattered. now the #/rips in each one is a random number from 1 to 3. try patching up each one.

I agree - if it can be done with a rule, it makes sense to do it that way in I7. Although this does require some mental back-tracking for those of us who are used to procedural programming.

I agree with this too- in order to do more with rules in Inform, I want a LOT more control over rule ordering. Is there a tab in the IDE that will tell you the order of rules, either in the Standard Library, extensions, or your own source?

I keep hearing, from multiple sources, about how it’s impossible (or at least counter-productive) to think creatively and critically at the same time. So I’ve been having a lot of fun switching off my critical thinking, which has always been weaker than my creative thinking anyway…

It isn’t an efficient way to program such a paragraph, as each line is its own loop.

See, that’s just “repeat with each one running through every worn thing” by another name (albeit briefer). I was aiming for not having to explicitly saying “I’m going to do a loop now! I’m going to use ‘each one’ as a variable now!” The idea is that the first Now statement uses the full description-of-objects, and each subsequently line just uses, as you say, an automatically-remembered whatchamacallit. Inform can tell where the loop ends by where the last place ‘each one’ appears. (I had used ‘each’ rather than ‘each one’ in my earlier example.)

Yeah. It’s called declarative programming, and the Superman examples I gave were basically Prolog with nicer (readable) syntax.

Er, the tab in the Index marked “rules”? Also, “actions” for rules that have actions in their name. Everything’s sorted into the order in which they’ll run.

Capmikee: I finally am able to get to this thread. It is an interesting set of problems.

I guess I am going to come at this from a strict procedural syntax angle. I am going to use EBNF to write the examples. I feel most language developers are pretty well versed in it. Unfortunately for the rest of the world, they are lost.

First off it looks to me like I7 starts with a pretty common understanding of if.

::= If |
If else

Expression has to resolve to a Boolean (true or false) so that the if will work. Many languages will use the reserved word then. It is helpful for all sorts of reasons.

This syntax permits an ambiguity:

If if else

The ambiguity can be resolved:

If begin if else end

We can make this statement because the language includes other productions such as:

::= |
::= |

::= |

::=

::= begin {;} end

The production ::= | allows me to rewrite a as a anywhere I see it. This production ::= | lets me rewrite a as a . The production ::= begin <statement {;} end lets me rewrite as what we commonly call a block.

So the following is syntactically correct::

begin
[list]statement-1;
statement-2;
begin [list]
statement-3;
statement-4;
statement-5;
end
statement-6;
statement-7[/list:u]
end [/list:u]

I could take all of the spaces and indentation out:

beginstatement-1;statement-2;beginstatement-3;statement-4;statement-5;endstatement-6;statement-7end

The parser understands both ways. It does not need spaces or indentation to understand what is going on. It uses the language tokens, syntax rules and semantic rules to make sense of the input stream. The fancy formatting is there only to help the person read and understand code.

What the reserved words begin and end represent is the block initiation token and the block termination token. Languages like C use { and } to be the block delimiters.

It works out that this particular set of productions has the form of an LL(1) grammar. It is my understanding that this is the predominate grammar used in programming languages. There is a technical reason we like the reserved word then to appear in conditionals and a block terminator token in compound statements. There has to be a closure set which is determinate. Otherwise the parser gets lost deciphering the production.

I will admit that my understanding of I7 syntax is a bit shaky. But in my other post I give examples where I7 is inconsistent in the way it handles nested if. I show that it has the rule that if there is a block anywhere in the if blocks must be used everywhere in the if. This flies in the face of what I would consider the ordinary understanding of nesting ifs and the usage of blocks.

Just to muddy the waters further. :wink: The following if statements are used to express some specific relationships.

First example: a transitive relationship.
If a Bank is part of a Channel and a Channel is part of a River, then a Bank is part of a River.

Second Example:a symmetric relationship.
If a Floodplain is adjacent to a River, then the River is adjacent to the Floodplain.

Third Example:an antisymmetric relationship.
If one River flows into another River, then the second River cannot flow into the first.

Fourth Example:an Inverse relationship.
If Water is contained in a river, then the River contains Water.

While they are all superficially the same if-then structure, semantically they have widely varying meanings.

One might say - while a condition is met such and so happens. While the house is on fire the fireman spray water. Syntactically it is not - If the house is on fire, then the fireman spray water. Also, the if may not require the fireman to spray the entire time. They could pull up to the fire, spray a gallon of water and then go home. I am inclined to think the if version was met, but certainly not they while version.

Why stop there? The fireman spray water on the house; because, the house is on fire. That seems to be closer to the notion than if-then. We can even invert the clause order. Because, the house is on fire; the fireman spray water on the house.

As has been suggested, we may have more “natural” ways to express causal relationships than if-then. In any case, I suggest that we are nibbling at the edges of a domain specific controlled English. I am inclined to the view that an organized model (ontology) of IF constructs expressed in that language will create a more powerful, easier to learn and use I7.

You are having way too much fun to keep this thread to yourselves. :stuck_out_tongue:

I would like to introduce a distinction between loop and iteration.

Loop is a flow of control construct. It lets the programmer write a set of instructions called the body of the loop once. The instructions in the body will be executed, in order, zero or more times. There are several commonly used ways to control the number of times the loop body is executed.

Infinite loop:

do
[list]loop body
end[/list:u]

A known number of times:

for LoopCounter equals 1 to 10 increment by 1 do
[list]loop body
end [/list:u]

conditional:

Test before loop body

[list]While a condition is met do
[list]loop body
end[/list:u]

Test after the loop body

repeat
[list]loop body
until a condition is met[/list:u]
[/list:u]

Exhaustive:

foreach element in A do
[list]loop body
end[/list:u]

On the other hand iteration is a construct that allows the programmer to traverse and access all elements in a container. By container I mean an abstract data type. It can be realized as any number of real data types, for example arrays, lists, or trees. An iterator can do something called traverse or visit the individual instances or elements of the data type. It can also provide access to the element which is the result of a traversal.

For most programmers the two concepts, loop and iteration, go hand-in-hand. We learned to use loops to traverse all the elements in an array and to access each element in turn. For example we can list each element in an array:

UpperBound:= NumberOfElements(SomeArray)-1;
for I:=0, UpperBound do
[list]show SomeArray[I]
end;[/list:u]

Languages can have other constructs which allow us to express the concept of iteration. Here is one that moves towards a declarative paradigm:

show foreach(SomeArray);

After what must seem like splitting a hair to most people we get to the punch line. We need to agree on the data types which the language recognizes. Once we agree on that, we have to decide on an appropriate iterator for each. Then we have to implement it in the syntax of the language. Languages do not have to be limited to the loop flow of control construct to express iteration.

So my question for the brainstorming part is this – what data types do we need?