On 2020-05-07 7:22 pm, Freeman Gilmore wrote:
Need lots of help this. Starting with this:
sum = #(lambda x
(define A (apply + x))
(display A))
#(sum 2 3 4 5) % 14 (from LilyPond Log)
I am guessing from reading “Extending LilyPond“ the above could be maid
into:
function =
(define-void-function
(arg1 arg2 …)
(type1? type2? …)
body)
This is one of my many tries: but nothing works:
sum = #(define-void-function (x)
(lambda x
(define A (apply + x))
(display A)))
{\sum 2 3 4}
There are several things going on here.
The lambda construct supports a few patterns for specifying the formals:
(lambda (a b c) ...)
(lambda args ...)
(lambda (x y . z) ...)
In the first case, the lambda has fixed arity of three and will bind the
arguments to the provided names in order, first argument to left-most
name.
In the second case, the lambda has unbounded variable arity and will
bind the arguments as a list to the provided name.
In the third case, the lambda has variable arity requiring at least two
arguments though having no maximum. Those first two arguments will bind
to the provided names in a manner similar to the first case where all
other arguments are bound to the final name as a list as in the second
case.
The define-*-function family of macros support the same syntax for
defining formals, however they also require specifying the signature of
the function using a list of type predicates:
(define-music-function (a b c) (type? type? type?) ...)
(define-scheme-function args (type? type? type? type?) ...)
(define-void-function (x y . z) (type? type? type? type? type?) ...)
Since the list of type predicates is finite, the arity of the syntax
function is bounded. The second case above, for instance, accepts
exactly four arguments and binds them to args as a list. In a similar
manner, the third case above accepts precisely five arguments--the first
two bind to x and y respectively, whereas the rest bind to z as a list.
Note that the signature does support optional arguments providing there
can be no confusion for other types and that the final type predicate is
non-optional. So the arity of these syntax functions can be variable,
but they will always have a minimum and maximum bound.
Attempting to apply this to your sum function:
%%%%
\version "2.20.0"
sum =
#(define-void-function
args
(number? number? number?)
(format #t "\nargs: ~s, sum: ~s" args (apply + args)))
\sum 2 3 5
\sum 8 13
\sum 21 34 55 89
%%%%
====
GNU LilyPond 2.20.0
Processing `lambda-args.ly'
Parsing...
args: (2 3 5), sum: 10
args: (21 34 55), sum: 110
lambda-args.ly:11:1: error: wrong type for argument 3.
Expecting number, found #<unspecified>
\sum 21 34 55 89
lambda-args.ly:11:15: error: syntax error, unexpected UNSIGNED
\sum 21 34 55
89
fatal error: failed files: "lambda-args.ly"
====
The problem here is that \sum requires no fewer than and no more than
three arguments, which is unlikely to be of much use.
We could make \sum more useful by accepting a list of numbers:
%%%%
\version "2.20.0"
sum =
#(define-void-function
(args)
(number-list?)
(format #t "\nargs: ~s, sum: ~s" args (apply + args)))
\sum 2, 3, 5
\sum 8, 13
\sum 21, 34, 55, 89
%%%%
====
GNU LilyPond 2.20.0
Processing `lambda-args.ly'
Parsing...
args: (2 3 5), sum: 10
args: (8 13), sum: 21
args: (21 34 55 89), sum: 199
Success: compilation successfully completed
====
This works because the parser knows how to look for a comma-separated
list of numbers of which can be matched by the number-list? type
predicate. But note that this list counts as a single argument, so we
need to specify the formals as (args), not args. If we omitted the
parentheses, then args would be bound to a list containing the list of
numbers.
-- Aaron Hill