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 <[email protected]> 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