[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: A question about a scheme function with two input notes
From: |
David Kastrup |
Subject: |
Re: A question about a scheme function with two input notes |
Date: |
Sat, 31 Dec 2022 03:47:11 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) |
Jean Abou Samra <jean@abou-samra.fr> writes:
> [This is the continuation of
> https://lists.gnu.org/archive/html/lilypond-user/2022-12/msg00321.html]
>
>
> Le 30/12/2022 à 15:07, David Kastrup a écrit :
>> You conflate "parsing" and "reading". For #{...#}, there is a
>> rudimentary scan for # and $
>
>
> Yes, I know that.
>
>
>> that tends to deliver false positives (which then just don't get
>> evaluated later on)
>
>
> This sounds worrisome.
Not particularly worrisome.
> Do you have examples of that happening?
"\\%" = "Huh?"
x = "What?"
sam =
#(define-music-function (x) (string?)
#{ \lyricmode { \% #x
} #})
\lyrics { "Hi" \sam "Hello" }
> The Scheme reader will throw an error that is incomprehensible
> for the user in case this happens and # or $ is followed by something
> that is not a valid Scheme expression, so avoiding false positives
> is important for correctness.
x is a valid Scheme expression here but escaped being treated as
closure.
>> and may get confused into
>> overlooking actual positives. \ offers a lot more potential for getting
>> this wrong.
>>> It would also make Guile evaluate one (lambda () <variable>) per use
>>> of \ in #{ #}, which I don't believe is costly.
>> It is. The optimisation of not putting up closures for most constants
>> made a relevant performance difference.
>
>
>
> I did a test with a file constructed using
>
> $ echo '\version "2.25.1"' > perftest.ly
> $ for i in `seq 10000`; do echo '##{ #1 #}' >> perftest.ly; done
>
> I pinned my CPUs at 2GHz (to reduce statistical noise) and measured:
>
> $ hyperfine -m 30 'master/build/out/bin/lilypond perftest.ly'
> Benchmark 1: master/build/out/bin/lilypond perftest.ly
> Time (mean ± σ): 1.446 s ± 0.021 s [User: 1.395 s, System:
> 0.107 s]
> Range (min … max): 1.410 s … 1.498 s 30 runs
>
> $ hyperfine -m 30 'build/out/bin/lilypond perftest.ly'
> Benchmark 1: build/out/bin/lilypond perftest.ly
> Time (mean ± σ): 1.609 s ± 0.083 s [User: 1.551 s, System:
> 0.108 s]
> Range (min … max): 1.539 s … 1.917 s 30 runs
>
>
> The second one is with the removal of the (or (symbol? expr) ...) test
> in parser-ly-from-scheme.scm. The difference is about 0.16s for 10,000
> expressions, or 16μs / expression.
Huh? You need to set it to #t rather than remove it.
> The Notation manual has a section on what it calls "substitution
> functions", which is separate from the section on music functions
> in the Extending manual, and I think that is for good reason.
> Those "substitution functions" have the form of a define-music-function
> where the body is just a #{ ... #}. There is little Scheme "programming"
> involved for that apart from cargo-cult copy&pasting of the
> define-music-function template and picking type predicates
> from the list in the documentation.
>
> I regularly see people (especially on lilypond-user-fr lately)
> wondering why returning #{ \book { ... } #} from a music function
> does not work, and that sort of thing.
> It's LilyPond's kind of "macro" facility, which is accessible to
> all users including those who know nothing about Scheme, and
> I think there is a point in making it behave more like users
> would expect ("just use variables like you always do, except
> that the variables change every time").
But there is a difference between variables and local bindings. This is
just serving to confuse people by comingling Scheme and LilyPond in an
incomprehensible manner.
--
David Kastrup