[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: how to repeat a scheme function that creates a Score
From: |
Jean Abou Samra |
Subject: |
Re: how to repeat a scheme function that creates a Score |
Date: |
Wed, 6 Apr 2022 08:35:12 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.7.0 |
Le 06/04/2022 à 07:40, Jeff Olson a écrit :
Two questions below re: (a) looping and (b) random seed.
In order to investigate some other problems I'm having in a large
project (pagination, memory usage) I learned enough scheme (barely) to
define a function that generates a new score with each invocation:
--
\version "2.22.0"
\include "gen-music.ily"
% each invocation of scr generates a new score of different length
pcn = 0
scr = #(define-scheme-function () ()
(set! pcn (1+ pcn))
#{
\score {
\header { piece = \markup{ "Piece " #(number->string pcn) } }
{ \gen-music \bar "|."} }
#} )
--
(The include file, gen-music.ily, is attached, and the above ~MWE is
also attached as MWE-do-scr.ly.)
Question (a):
My main question is how to write a scheme function that will invoke my
scr function N times, where N could be a number like 1000.
So far the only way I know how to do multiple invocations is by
explicitly hard-coding "\scr \scr ..." in blocks and copy/pasting
those blocks.
Looking for a better way, I realized I don't even know how to get one
line of scheme to do 2 invocations (needed for tail recursion
approach). I can make them execute, in some cases, but not to produce
pdf output (never gets to "Interpreting music..."). Part of this may
be #(scr) vs $(scr). The attached MWE file has lots of my failed
attempts commented out (I'm at a teachable moment if someone has a
moment to teach). Or just point me to the right manual page(s).
Here is a piece of code that works:
$@(map (lambda (i) (scr)) (iota 10))
Now let's go through your attempt to see why they are failing.
#(define scors (lambda (n) (if (= n 1) (scr) ((scr) (scors (- n 1) )))))
#(scors 2)
This one is trying to apply a score (the result of (scr)) as a
function. A score is not a function. Also, if n = 1, (src) is
generated, which is not a list, so at the end of the day you
get an "improper list" (something that looks like a list but
doesn't have the empty list at the end of the cdr chain).
Rather do
#(define scors (lambda (n) (if (= n 0) '() (cons (scr) (scors (- n 1) )))))
#(scors 2)
That doesn't error out (scors is applied successfully), but no output
either, as you noticed. The problem is that when LilyPond reads a
toplevel expression introduced by #, it refrains from interpreting the
result, since that is the main way you can write code that operates via
side effects on the toplevel (think #(define ...) and such). You need
to be a little more insistent, with $.
#(define scors (lambda (n) (if (= n 0) '() (cons (scr) (scors (- n 1) )))))
$(scors 2)
Now that gives the error "bad expression type". Indeed, LilyPond knows how
to interpret a score, but not a list of scores. So you need to splice
the list into several scores that LilyPond will interpret separately.
You can do that with $@. Thus, this works:
#(define scors (lambda (n) (if (= n 0) '() (cons (scr) (scors (- n 1) )))))
$@(scors 2)
Now to your second attempt:
#(for-each (lambda (ignore) (scr)) '(1 2 3 4 5))
This has the same problem of # vs. $@. Also, it is using for-each, which
applies a function for its side effect but does not remember the result.
In this case, you want a list of the results, which is what map is for.
$@(map (lambda (ignore) (scr)) '(1 2 3 4 5))
Now to
#(begin (scr) (scr) (scr))
and
$(begin (scr) (scr) (scr))
The first discards the result because of #. The second calls src thrice, and
discards the results of the two first invocations -- that's what begin is
for. As Valentin pointed out while I was writing this, you could use
add-score
to let LilyPond know about your score via a side effect rather than by
returning
them.
#(begin
(add-score (scr))
(add-score (scr))
(add-score (scr)))
For the examples at the end, you need $@mine, which is the only one you
didn't try :-)
Best,
Jean