lilypond-user
[Top][All Lists]
Advanced

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

Re: Having trouble understanding optional and variable amount of argumen


From: Thomas Morley
Subject: Re: Having trouble understanding optional and variable amount of arguments
Date: Sat, 3 Mar 2018 15:34:58 +0100

2018-03-01 18:31 GMT+01:00 Stefano Troncaro <address@hidden>:
> I didn't know about \default or the dot/comma separated number/symbol lists!
> I can see those being useful in some circumstances. I was thinking about
> cases where an undefined amount of things different than symbols or numbers
> are required, and the closest I can imagine is chaining functions to create
> the illusion of a variable amount of arguments, like this:
>>
>> \version "2.19.80"
>>
>> #(define (end-list? obj)
>>    (and (list? obj)
>>         (let ((item (last obj)))
>>           (and (symbol? item)
>>                (equal? "end" (symbol->string item))))))
>>
>> end = #(list 'end)
>>
>> #(define (el->curated-el el)
>>    (delete 'end el))
>>
>> untilEnd =
>> #(define-void-function (proc el) (procedure? end-list?)
>>    (let ((curated-el (el->curated-el el)))
>>      (for-each
>>       (lambda (elem)
>>         (proc elem))
>>       curated-el)))
>>
>> selfAppending =
>> #(define-scheme-function (e-l) (end-list?)
>>    (let ((self-input (list (cons 1 2) (cons 3 4))))
>>      (append self-input e-l)))
>>
>> selfAppendingInput =
>> #(define-scheme-function (input e-l) (scheme? end-list?)
>>    (append (list input) e-l))
>>
>> \relative c'' {
>>   c d e f
>>   \untilEnd #pretty-print
>>     \selfAppending
>>     \selfAppendingInput #'(some useful input?)
>>     \selfAppendingInput #selfAppending
>>     \selfAppending
>>     \end
>>   g a b c
>> }
>
> This structure just happens to work for something I'm trying now but I can
> see it being too narrow in general.
>
> @Urs, I not familiar with \with blocks, I'll take a look at the oll-core
> code and experiment a bit with it. Maybe I'll be able to help.
>
> 2018-03-01 4:55 GMT-03:00 David Kastrup <address@hidden>:
>>
>> Stefano Troncaro <address@hidden> writes:
>>
>> > Thank you! I see that this is not an option then. Also, I now understand
>> > why I couldn't make the optional arguments work, since I always left
>> > them
>> > for last.
>> >
>> > Do you know if it is possible to have a flexible amount of optional
>> > arguments that appear before the last mandatory one? Say, for example
>> > (define-music-function (arg1 args music) (number? ??? ly:music?) where
>> > arg1
>> > and music are mandatory, and basically everything between arg1 and the
>> > next
>> > music expression is compacted into a list and accessed as args in the
>> > body
>> > of the function. Not with that syntax necessarily, but something that
>> > allows for that kind of usage?
>>
>> You know that a number or symbol list can be entered as a
>> comma-separated list?
>>
>> --
>> David Kastrup

Hi Stefano,

I was always fine with one optional list?-predicate (this may ofcourse
be an alist) and sorting/processing this list in the body of the
music-function.
Or things like (lambda (arg . rest) ...) in some cases or the
comma-separated list (as already mentioned).

If you really want to go for a music-function with arbitrary arguments
here some thoughts.

Beside the result has still limitations:
- the amount of possible arguments has to be specified (ofcourse you
can go for something like 20, which should really be enough (currently
5 are defined)
- all those arguments have to be of kind (not (ly:music ...)), which
makes it impossible to enter a second music-argument.
- maybe more, it's not tested beyond the given examples
I expect David K will point out more weaknesses ... lol

I deleted the not matching doc-strings from define-syntax-function and
define-music-function.
Look into music-functions.scm to read them.

\version "2.19.65"

#(defmacro-public define-my-syntax-function
                  (args-amount type args signature . body)
  (define (has-parser/location? arg where)
    (let loop ((arg arg))
      (if (list? arg)
          (any loop arg)
          (memq arg where))))
  (define (currying-lambda args doc-string? body)
    (if (and (pair? args)
             (pair? (car args)))
        (currying-lambda (car args) doc-string?
                         `((lambda ,(cdr args) ,@body)))
        (let* ((compatibility? (if (list? args)
                                   (= (length args) (+ 2 (length signature)))
                                   (and (pair? args) (pair? (cdr args))
                                        (eq? (car args) 'parser))))
               (realargs (if compatibility? (cddr args) args)))
          `(lambda ,realargs
             ,(format #f "~a\n~a" realargs (or doc-string? ""))
             ,@(if (and compatibility?
                        (has-parser/location? body (take args 2)))
                   `((let ((,(car args) (*parser*)) (,(cadr args) (*location*)))
                       ,@body))
                   body)))))

  (let ((docstring
         (and (pair? body) (pair? (cdr body))
              (if (string? (car body))
                  (car body)
                  (and (pair? (car body))
                       (eq? '_i (caar body))
                       (pair? (cdar body))
                       (string? (cadar body))
                       (null? (cddar body))
                       (cadar body))))))

    (let ((new-args
            (map
              (lambda (i)
                (string->symbol (format #f "~a-~a" (car args) i)))
              (iota args-amount 1 1))))
      (set! args (append new-args (cdr args)))
      (set! signature
            (append
              (make-list args-amount (car signature))
              (cdr signature))))

    ;; When the music function definition contains an i10n doc string,
    ;; (_i "doc string"), keep the literal string only
    `(ly:make-music-function
      (list ,@(map (lambda (pred)
                     (if (pair? pred)
                         `(cons ,(car pred)
                                ,(and (pair? (cdr pred)) (cadr pred)))
                         pred))
                   (cons type signature)))
      ,(currying-lambda args docstring (if docstring (cdr body) body)))))

#(defmacro-public define-my-music-function rest
  `(define-my-syntax-function
    ,(car rest)
    (ly:music? (make-music 'Music 'void #t))
    ,@(cdr rest)))

tst =
#(define-my-music-function 5 (xy mus)
  (((lambda (x) (not (ly:music? x))) #f)
   ly:music?)
  "DOCME"
  (format #t "\n\tTHIS IS EXPERIMANTAL CODE. DON'T USE IT FOR SERIOUS WORK\n\n")
  (pretty-print (list xy-1 xy-2 xy-3 xy-4 xy-5))
  (if (number-pair? xy-2)
      #{ \once \override Rest.extra-offset = #xy-2 $mus #}
      #{ #}))

{ \tst r4 r2 r4 }
{ \tst #'a r4 r2 r4 }
{ \tst #'a #(cons 1 2) r4 r2 r4 }
{ \tst #'a #(cons 1 2) #'(cons 3 4) r4 r2 r4 }
{ \tst #'a #(cons 1 2) #'(cons 3 4) #'(some useful input?) r4 r2 r4 }
{ \tst #'a #(cons 1 2) #'(cons 3 4) #'(some useful input?) #"foo" r4 r2 r4 }


Cheers,
  Harm



reply via email to

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