Incomplete draft: do not cite!

Again, the basic execution strategy of languages like Step makes it easy to ask questions about whether some execution path exists.  We can ask questions about all possible paths too, but we have to use higher-order tasks to do that.

Implies

We talked about Implies earlier.  The predicate:

[Implies ?p ?q]

is so named because, if it's true, then it means ?q is true in all situations where ?p is true.  Or to put it another way, there are no situations where ?p is true (i.e. no solutions to ?p) where ?q is false (where ?q fails).  In fact, if it weren't built in, we could define Implies ourselves:

Implies ?p ?q: [Not [And ?p [Not ?q]]]

Under the hood, this is going to work by finding all solutions to ?p and then for each one, testing if ?q is true.  For example, if we use our food preferences example:

[predicate]
Likes tanya sushi.
Likes tanya burgers.
Likes tanya mexican.
Likes jayden burgers.
Likes jayden ethiopean.
# Kimiko likes everything
Likes kimiko ?.
# Everyone likes pizza.
Likes ? pizza.

we might ask "does everyone who likes burgers like pizza?"  That would be:

[Implies [Likes ?who burgers] [Likes ?who pizza]]

You can try it out:

# Try: [Implies [Likes ?who burgers] [Likes ?who pizza]]
[predicate]
Likes tanya sushi.
Likes tanya burgers.
Likes tanya mexican.
Likes jayden burgers.
Likes jayden ethiopean.
# Kimiko likes everything
Likes kimiko ?.
# Everyone likes pizza.
Likes ? pizza.

You get the answer “yes”, but it doesn't have a binding for the variable ?who.  That makes sense because we weren't asking for a specific person who liked burgers and pizza, we were asking if everyone who liked burgers liked pizza.  So there's no one ?who to report back.

ForEach

Implies is useful when calling predicates.  But what if we wanted to ask it to print everyone who liked burgers?  You could write it this way:

# Try: [WhoEats burgers]
WhoEats ?x: [Implies [Likes ?who ?x] [Write ?who]]
[predicate]
Likes tanya sushi.
Likes tanya burgers.
Likes tanya mexican.
Likes jayden burgers.
Likes jayden ethiopean.
# Kimiko likes everything
Likes kimiko ?.
# Everyone likes pizza.
Likes ? pizza.

But it reads a little strangely to say "implies Write."  Here it reads a little better to use ForEach:

# Try: [WhoEats burgers]
WhoEats ?x: [ForEach [Likes ?who ?x] [Write ?who]]
[predicate]
Likes tanya sushi.
Likes tanya burgers.
Likes tanya mexican.
Likes jayden burgers.
Likes jayden ethiopean.
# Kimiko likes everything
Likes kimiko ?.
# Everyone likes pizza.
Likes ? pizza.

For these purposes, ForEach is identical to Implies, it just has a more useful title.  However, there is one difference, which is that [Implies ?p ?q] will fail if ?q ever fails when Implies calls it.  ForEach actually ignores whether q fails or not.

State updates in loops

[ForEach ?p ?q] and [Implies ?p ?q] will collect all the output generated by the different calls to ?q.  It will also accumulate any changes to global variables or fluents that ?q makes.  However, it will ignore any output or changes made by ?p.

Niche loops (ignore this if you aren't a power-user)

DoAll

[Implies ?p ?q] and [ForEach ?p ?q] consider all the possible execution paths of ?p but for each of those paths, only finds one solution of ?q.  DoAll takes a series of calls, and finds all the solutions to the sequence and gives you all their outputs:

[DoAll ?call1 ?call2 ...]

Note that this only accumulates output; it ignores all state changes.

AccumulateOutputWithSeparators

This is mostly used for printing comma-separated lists of things

[AccumulateOutputWithSeparators ?generator ?printer ?separator ?finalSeparator]

This is mostly like saying [ForEach ?generator ?printer] except rather than just printing the outputs of ?printer, it separates them by ?separator, putting ?finalSeparator before the end.  If we use it for our WhoEats example:

# Try: [WhoEats burgers]
WhoEats ?x: [AccumulateOutputWithSeparators [Likes ?who ?x] [WriteCapitalized ?who] "," "and"]
[predicate]
Likes tanya sushi.
Likes tanya burgers.
Likes tanya mexican.
Likes jayden burgers.
Likes jayden ethiopean.
# Kimiko likes everything
Likes kimiko ?.
# Everyone likes pizza.
Likes ? pizza.

we get “Tanya, Jayden and Kimiko”, which looks a little nicer than if we just had spaced between them.