First of all, I apologize for the delayed response, I wanted to write back
earlier but I couldn't find the time to delve into your last suggestions.
Thank you for the useful replies!

@Harm
I don't understand most of what the code you provided is doing, only that
it works. It's far too advanced for me, so (unfortunately) dissecting it
would require much more time than what I currently have. It looks
interesting though, I hope I can study it in more detail later.

I did manage to look a little bit into macros, and I have a question if you
don't mind. This chapter of the guile documentation
<https://www.gnu.org/software/guile/docs/docs-1.8/guile-ref/Syntax-Rules.html#Syntax-Rules>
explains about define-syntax and syntax-rules. They appear to work but
generate an error message about wrong number of arguments to a music
function. Is that module not usable in Lilypond?

Example that works:

> \version "2.19.80"
> #(define-macro (test conditional true false)
>    `(if ,conditional
>         ,true
>         ,false))
>
> #(test #t (display "I'm true!\n") (display "I'm false!\n"))
>
> Example that works but creates an error, stopping the file from compiling:

> \version "2.19.80"#(use-syntax (ice-9 syncase))
>
> #(define-syntax test
>    (syntax-rules ()
>      ((test conditional true false)
>       (if conditional
>           true
>           false))))
>
> #(test #t (display "I'm true!\n") (display "I'm false!\n"))
> %%% Creates the output:
> %{
> file.ly:5:2: error: GUILE signaled an error for the expression beginning here
> #
>  (define-syntax test
> I'm true!
> Wrong number of arguments to #<Music function #<procedure #f (arg)>>
> %}
>
>
@Urs
I looked into your examples and \with blocks are very useful.

You said earlier that you were thinking about how to make it so that the
context-mod could have required arguments, default values for missing ones,
and even predicates. I was thinking that context-mod->props could be made
to accept this information as an optional argument. Then it can return a
'curated' list of props or raise warnings/errors. That I think shouldn't be
difficult to do. Although I'm undecided on what would be a convenient way
of storing the 'requirement data'. The obvious one to me is an alist with a
structure like this: `((key1 . (required . #t)) (key2 . ((default . 9)
(pred . ,number?))) ...), but I'm not sure. What do you think?

2018-03-03 11:34 GMT-03:00 Thomas Morley <thomasmorle...@gmail.com>:

> 2018-03-01 18:31 GMT+01:00 Stefano Troncaro <stefanotronc...@gmail.com>:
> > 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 <d...@gnu.org>:
> >>
> >> Stefano Troncaro <stefanotronc...@gmail.com> 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
>
_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to