lilypond-user
[Top][All Lists]
Advanced

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

Re: define-void-function


From: Aaron Hill
Subject: Re: define-void-function
Date: Thu, 07 May 2020 20:31:41 -0700
User-agent: Roundcube Webmail/1.4.2

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



reply via email to

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