* Macro to prepend element to list @ 2021-03-20 14:24 Jean Abou Samra 2021-03-20 16:04 ` Linus Björnstam 0 siblings, 1 reply; 5+ messages in thread From: Jean Abou Samra @ 2021-03-20 14:24 UTC (permalink / raw) To: guile-user Hello, I find myself frequently using the following macro: (define-macro (prepend! thing lst) `(set! ,lst (cons ,thing ,lst))) Have I missed a module somewhere that does this kind of things? At least, I couldn't find anything in SRFIs. It may also be the case that this is too specific to certain non-functional usages (LilyPond in my case). Thanks in advance, Jean Abou Samra ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Macro to prepend element to list 2021-03-20 14:24 Macro to prepend element to list Jean Abou Samra @ 2021-03-20 16:04 ` Linus Björnstam 2021-03-20 17:05 ` Jean Abou Samra 0 siblings, 1 reply; 5+ messages in thread From: Linus Björnstam @ 2021-03-20 16:04 UTC (permalink / raw) To: Jean Abou Samra, guile-user Well, mutating like that is not very common, except for maybe with alists. In which situations are you mutating the list like that? Usually you would build a reverse list using a recursive function and an accumulator, which can be done without set! (which has a boxing overhead). -- Linus Björnstam On Sat, 20 Mar 2021, at 15:24, Jean Abou Samra wrote: > Hello, > > I find myself frequently using the following macro: > > (define-macro (prepend! thing lst) > `(set! ,lst (cons ,thing ,lst))) > > Have I missed a module somewhere that does this kind of things? > At least, I couldn't find anything in SRFIs. It may also be the > case that this is too specific to certain non-functional usages > (LilyPond in my case). > > Thanks in advance, > Jean Abou Samra > > > ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Macro to prepend element to list 2021-03-20 16:04 ` Linus Björnstam @ 2021-03-20 17:05 ` Jean Abou Samra 2021-03-20 18:10 ` Linus Björnstam 0 siblings, 1 reply; 5+ messages in thread From: Jean Abou Samra @ 2021-03-20 17:05 UTC (permalink / raw) To: Linus Björnstam, guile-user [-- Attachment #1: Type: text/plain, Size: 1293 bytes --] Le 20/03/2021 à 17:04, Linus Björnstam a écrit : > Well, mutating like that is not very common, except for maybe with alists. > > In which situations are you mutating the list like that? Usually you would build a reverse list using a recursive function and an accumulator, which can be done without set! (which has a boxing overhead). Mostly to mutate properties of LilyPond's probs (property objects). This works somewhat like Guile's object properties. For example, to add articulations on notes: \version "2.23.1" #(define-macro (prepend! thing lst) `(set! ,lst (cons ,thing ,lst))) addStaccato = #(define-music-function (music) (ly:music?) (map-some-music (lambda (m) (if (music-is-of-type? m 'note-event) (prepend! (make-music 'ArticulationEvent 'articulation-type "staccato") (ly:music-property m 'articulations))) #f) music)) \addStaccato { c'4 d' e'8 f' g' a' } (Output attached.) It is also of use in so-called engravers (it's harder to find a simple use case for these). I guess all of this is so LilyPond-specific that it suits better in my personal libraries, and maybe upstream if I see a compelling use case in the code base. Thanks! Jean [-- Attachment #2: prepend-example.ly --] [-- Type: text/x-lilypond, Size: 435 bytes --] \version "2.23.1" #(define-macro (prepend! thing lst) `(set! ,lst (cons ,thing ,lst))) addStaccato = #(define-music-function (music) (ly:music?) (map-some-music (lambda (m) (if (music-is-of-type? m 'note-event) (prepend! (make-music 'ArticulationEvent 'articulation-type "staccato") (ly:music-property m 'articulations))) #f) music)) \addStaccato { c'4 d' e'8 f' g' a' } [-- Attachment #3: prepend-example.pdf --] [-- Type: application/pdf, Size: 27950 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Macro to prepend element to list 2021-03-20 17:05 ` Jean Abou Samra @ 2021-03-20 18:10 ` Linus Björnstam 2021-03-20 20:16 ` Jean Abou Samra 0 siblings, 1 reply; 5+ messages in thread From: Linus Björnstam @ 2021-03-20 18:10 UTC (permalink / raw) To: Jean Abou Samra, guile-user I see! To be honest, this seems like a guile-1.8ism... I don't think such code would work for guile2 though 3. Why? Because your are mutating a pointer local to your procedure, not the actual data pointed to by the music property You are modifying the pointer to the list returned by the call, not the list where it is stored. I don't know enough lilypond, but a more standard way of doing that would be something like (ly:music-property-set! m 'articulations (cons (make-music 'ArticulationEvent 'articulation-type "staccato") (ly:music-property m 'articulations))) (or a shorthand thereof). More verbose, sure, but also standard scheme... This could of course be abstracted away in some nicer way, like something I just pulled out of my posterior without much prior knowledge of lilypond (except for a fingering chart for bassoon I maintain): (update! (select '(note-event 'artuculations)) (lambda (p) (cons (make-music ...) m))) This could be done with higher order functions and passing lambdas around without having to rely on macros... -- Linus Björnstam On Sat, 20 Mar 2021, at 18:05, Jean Abou Samra wrote: > Le 20/03/2021 à 17:04, Linus Björnstam a écrit : > > > Well, mutating like that is not very common, except for maybe with alists. > > > > In which situations are you mutating the list like that? Usually you would build a reverse list using a recursive function and an accumulator, which can be done without set! (which has a boxing overhead). > > > Mostly to mutate properties of LilyPond's probs (property objects). > This works somewhat like Guile's object properties. For example, to > add articulations on notes: > > \version "2.23.1" > > #(define-macro (prepend! thing lst) > `(set! ,lst (cons ,thing ,lst))) > > addStaccato = > #(define-music-function (music) (ly:music?) > (map-some-music > (lambda (m) > (if (music-is-of-type? m 'note-event) > (prepend! (make-music 'ArticulationEvent 'articulation-type > "staccato") > (ly:music-property m 'articulations))) > #f) > music)) > > \addStaccato { c'4 d' e'8 f' g' a' } > > (Output attached.) > > It is also of use in so-called engravers (it's harder > to find a simple use case for these). I guess all of this > is so LilyPond-specific that it suits better in my personal > libraries, and maybe upstream if I see a compelling use > case in the code base. > > Thanks! > Jean > > > Attachments: > * prepend-example.ly > * prepend-example.pdf ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Macro to prepend element to list 2021-03-20 18:10 ` Linus Björnstam @ 2021-03-20 20:16 ` Jean Abou Samra 0 siblings, 0 replies; 5+ messages in thread From: Jean Abou Samra @ 2021-03-20 20:16 UTC (permalink / raw) To: Linus Björnstam, guile-user Le 20/03/2021 à 19:10, Linus Björnstam a écrit : > I see! > > To be honest, this seems like a guile-1.8ism... I don't think such code would work for guile2 though 3. Why? Because your are mutating a pointer local to your procedure, not the actual data pointed to by the music property You are modifying the pointer to the list returned by the call, not the list where it is stored. > > I don't know enough lilypond, but a more standard way of doing that would be something like (ly:music-property-set! m 'articulations (cons (make-music 'ArticulationEvent 'articulation-type "staccato") (ly:music-property m 'articulations))) (or a shorthand thereof). > > More verbose, sure, but also standard scheme... Well, not sure what you mean exactly, but ly:music-property is defined with a setter: (define-public ly:music-property (make-procedure-with-setter ly:music-property ly:music-set-property!)) which makes the code equivalent to (ly:music-set-property! m 'articulations (cons ... (ly:music-property m 'articulations))), doesn't it? > This could of course be abstracted away in some nicer way, like something I just pulled out of my posterior without much prior knowledge of lilypond (except for a fingering chart for bassoon I maintain): > > (update! (select '(note-event 'artuculations)) (lambda (p) (cons (make-music ...) m))) > > This could be done with higher order functions and passing lambdas around without having to rely on macros... Indeed, we could do things along these lines: \version "2.23.1" #(define (ly:music-transform-property! music prop func) (ly:music-set-property! music prop (func (ly:music-property music prop)))) addStaccato = #(define-music-function (music) (ly:music?) (map-some-music (lambda (m) (if (music-is-of-type? m 'note-event) (ly:music-transform-property! m 'articulations (lambda (elts) (cons (make-music 'ArticulationEvent 'articulation-type "staccato") elts)))) #f) music)) \addStaccato { c'4 d' e'8 f' g' a' } It is more verbose for prepending elements, but much more versatile, and 'cute' from (srfi srfi-26) can make the call more compact as well. Best regards, Jean ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2021-03-20 20:16 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-03-20 14:24 Macro to prepend element to list Jean Abou Samra 2021-03-20 16:04 ` Linus Björnstam 2021-03-20 17:05 ` Jean Abou Samra 2021-03-20 18:10 ` Linus Björnstam 2021-03-20 20:16 ` Jean Abou Samra
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).