lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Questions about using Scheme with Lilypond


From: Tom Brennan
Subject: Re: Questions about using Scheme with Lilypond
Date: Mon, 16 Nov 2020 13:28:02 -0500

Hi Aaron

Thanks. That's very helpful. It looks like from your example you linked to that there's probably a way to do just about anything in lilypond with Scheme, and I just need to dive into the scm library files. The other part is just learning how Scheme is different from Clojure (which is currently the only lisp I'm familiar with).

Re: arity, the (admittedly unclear) question wasn't whether or not scheme supports multi-arity, but whether you can "splat" any list (doesn't have to be from args), into a block of lilypond code, i.e.,

%%%
\version 2.20.0
foo = #(lambda the_rest #{
    \bookpart {
        \score_one
        \score_two
        #the_rest % <= splat: assuming `the_rest` is a list of scores
    }
#})
%%%%

The above doesn't work for reasons other than the lambda's arity, and for something like the above case, it looks like I'm probably better off using some procedures form the scm library like `add-score` or something lower level making use of `ly:parser-lookup` such as is done here:

```lily-library.scm
(define-public (add-score score)
(cond
((ly:parser-lookup '$current-bookpart)
((ly:parser-lookup 'bookpart-score-handler)
(ly:parser-lookup '$current-bookpart) score))
((ly:parser-lookup '$current-book)
((ly:parser-lookup 'book-score-handler)
(ly:parser-lookup '$current-book) score))
(else
((ly:parser-lookup 'toplevel-score-handler) score))))
```

But the question of whether you can apply a given list as arguments to a lilypond directive like I'm exemplifying with "the_rest" above -- still unclear about what is allowed in terms of interop with Scheme in these blocks. Does that question make sense? That's why I brought up macros, because in a general sense they make it possible to do (in Clojure, anyway) "unquote-splicing", obviating using something like `apply`, etc. But since you're in a lilypond block, it's just not clear to me what is allowed there in terms of interpolating scheme values.

Thanks again
Tom


On Sun, Nov 15, 2020 at 6:07 PM Aaron Hill <lilypond@hillvisions.com> wrote:
On 2020-11-15 12:03 pm, Tom Brennan wrote:
> I'd like to create a function that would allow me to create a
> `bookpart`
> from a list of arguments. E.g.,
>
> [...]
>
> Is this kind of thing possible?

Yes-ish, see my post [1] last month about "returning" books and book
parts.

[1]:
https://lists.gnu.org/archive/html/lilypond-user/2020-10/msg00406.html


> 2. Applying variadic arguments (i.e., "splat"). E.g., in Clojure, you
> can
> do something like this:
>
> [...]
>
> but you can't just throw a list in right there, right? It would need to
> be
> expanded, in the `apply` sense. I assume Guile has macros, like
> Clojure,
> but I don't know how to use them yet. Would that path lead me to
> success
> here, though?

Guile does support macros, although these are not needed for procedures
of variable arity.  Consider:

%%%%
\version "2.20.0"

#(define (foo . args) (format #t "\nargs=~s" args))
#(foo 1 2)
#(foo 'a 'b 'c)

#((lambda args (format #t "\nargs=~s" args)) 3 'd)
%%%%

====
Parsing...
args=(1 2)
args=(a b c)
args=(3 d)
====

The problem you are hitting is that music functions must have fixed
arity.  There is limited support for optional arguments, but the parser
ultimately needs to know how much input will be consumed by a function. 
Otherwise, you could invoke a music function and potentially read to the
end of the file.

To work around this limitation, you can leverage existing constructs
that contain variable numbers of things.  Consider a function that needs
to accept one or more pitches.  You could instead accept ly:music? so
multiple pitches are specified within curly braces (i.e. sequential
music).  The music-pitches procedure will handle extracting the pitches
from the provided music:

%%%%
\version "2.20.0"

baz = #(define-void-function (pitches) (ly:music?)
   (format #t "\npitches=~s" (music-pitches pitches)))
\baz a
\baz { b d f }
%%%%

====
Parsing...
pitches=(#<Pitch a >)
pitches=(#<Pitch b > #<Pitch d > #<Pitch f >)
====


-- Aaron Hill


reply via email to

[Prev in Thread] Current Thread [Next in Thread]