[Sorry! I wrote this two days ago on a train in one of the famous German
cell connection dead zones - and then forgot to actually send it later.]

Hi Kieren,

The last "m" in your innermost (if ...) is unnecessary: As with the difference between "for" and 
"map" in plain Scheme, the return value of the lambda function in for-some-music gets discarded ("for" 
functions are supposed to _do_ something, not _return_ something). So your branch stating "... else return m" can be 
omitted.
Excellent.

Well, modulo David's correction. :-)

It's true that the lambda function in for-some-music isn't supposed to
return the music it has produced. But since its return value determines
(as a boolean) whether to recurse, we should make sure to

- return ##f if our music argument m is not a note-event (but might
contain one)
- return a true value if we don't want to recurse any further. Since
note-events usually don't contain any other music, this might never
actually matter, but it is good to also read your code in the note-event
case and check which value gets returned in which case.

It might be worth noting that an (if condition then-clause) expression
without an else-clause returns and unspecified value if condition is #f.
https://www.gnu.org/software/guile/manual/html_node/Conditionals.html

Next, as you already hinted: If you use the same expression more than once 
(here (ly:music-property m 'pitch)), it is usually reasonably to store it in a 
variable, i.e. use (let ...).
Why wouldn’t I use let* here? I 
readhttps://extending-lilypond.gitlab.io/en/scheme/local-variables.html#let-syntax,
 and unless there’s some big-ticket efficiency problem under the hood, I don’t 
see why anyone would use let instead of let*.
I do not know if there are efficiency differences between let and let*
(but I doubt it). Personally, I use let if I don't need let*, since this
way, when I re-read my code, I immediately know that the let-assignments
do not depend on one another.

we rather want a list of pairs (old-pitch . new-pitch)
That’s the interface I was thinking of.

In order to construct such a list of pairs from two music inputs as above, (map 
...) provides a very elegant way.
In the case of a simple scale,

    \adjustPitches scaleIn scaleOut

and then post-processing into lists, etc., makes some sense. But what about 
sending in pairs instead? e.g.

    \adjustPitches ((ces c) (c b') (e g))

There would be the question of whether the user wants to process each pair 
consecutively (e.g., all ces become c, then all c [including the old ces] 
become b', etc.)… Maybe both options made available, with either a switch or 
optional parameter(s)?

The problem is that (ces c), or rather (ces . c), is Scheme syntax (and
requires ` and , when ces and c should not be taken as mere symbols),
but we don't have note name input in Scheme. So this would actually be
something like

(list (cons #{ ces #} #{ c #}) (cons #{ c #} #{ b #}))

or

`((,#{ ces #} . ,#{ c #}) (,#{ c #} . ,#{ b #}))

both of which make my brain hurt :-).

A way of inputting the pitches in LilyPond syntax might be much more
convenient. Possibilites that come to mind might be

{ ces c e } { c b' g }

{ ces c c b' e g }

{ <ces c> <c b'> <e g> }

etc., all of which are comparatively easy to implement (the first one
probably being the easiest).

Lukas

Reply via email to