29 Let Bindings
A let binding gives a name to a path tail so the named result can be used in the
expression that follows.
The previous chapter showed that this expression forms products of independently reached values:
x.(v*v as product)
If the intention is to square each value reached by v, bind the reached value once:
x.(let a = v in a*a as product)
The name a refers to the value reached by the binding. The calculation uses that
same named value twice.
Naming an intermediate calculation
let can also name an intermediate calculation:
u.course.session.time.(
let duration = endMinute-startMinute in duration as durationMinutes)
This is deliberately a small example. The calculation is simple enough to write
without let, but the shape becomes useful when the intermediate value is used more
than once.
Keeping an outer value available
The chapter on this showed that let can preserve an outer value before
navigation changes the current value. In the following expression, c names the
current course before the path enters its sessions:
u.course.(let c = this in session.(c.code as courseCode, room))
Inside session.(...), the current value is a session. The name c still refers
to the outer course.
Gotcha: this changes inside path tails
This expression tries to compare each session with the other sessions for the same course:
u.course.session.(let s=this in
session.[this ≠ s])
The unqualified inner session is evaluated from the current session, not from the
course. Save the course first, then navigate back through the saved course:
u.course.(let c=this in
session.(let s=this in
c.session.[this ≠ s]))
Use let outer=this in ... before entering a path tail when the nested expression
still needs the outer object.
Let bindings inside filters
A let binding can appear inside a filter condition:
u.course.session.time.[let duration = endMinute-startMinute in duration > 120]
The filter keeps the time slots whose calculated duration is greater than 120.