lilypond-user
[Top][All Lists]
Advanced

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

Re: scheme set list function


From: Thomas Morley
Subject: Re: scheme set list function
Date: Tue, 9 Apr 2019 00:41:10 +0200

Am Mo., 8. Apr. 2019 um 13:17 Uhr schrieb Aaron Hill <address@hidden>:
>
> On 2019-04-08 2:48 am, Thomas Morley wrote:
> > foo =
> > #(let ((x (cons 1 0)))
> >   (define-scheme-function (arg)(symbol?)
> >     (case arg
> >       ((indent) (set! x (cons (car x) (1+ (cdr x)))))
> >       ((increase) (set! x (cons (1+ (car x)) 0)))
> >       ((reset) (set! x (cons 1 0))))
> >     (if (zero? (cdr x))
> >         (format #f "~a" (car x))
> >         (format #f "~a.~a" (car x) (cdr x)))))
> >
> > [ . . . ]
> >
> > I'm still not happy with those set-whatever!-thingies. I was beaten
> > too often. Maybe someone comes up with a better approach.
>
> Using set! is perfectly fine as long as you encapsulate things well.
> Your use of let to define a local variable minimizes the chance that
> folks would be able to interfere with or even care about such
> modification.  However, your usage means there is still a "global" x
> that is shared amongst all of the usage of foo.

Yep, for all "\foo".

>
> Guile's manual talks about object orientation and uses a pattern not at
> all dissimilar to what you provided above.  Consider the following:
>
> %%%%
> \version "2.19.82"
>
> #(define (make-section-numberer)
>    ;; Note that numbers are being stored little-endian.
>    (let ((numbers '(1)))
>      (define (get-section) (format #f "~{~d~^.~}" (reverse numbers)))
>      (define (next-section)
>        (set! numbers (cons (1+ (car numbers)) (cdr numbers)))
>        (get-section))
>      (define (indent)
>        (set! numbers (cons 1 numbers))
>        (get-section))
>      (define (unindent)
>        (if (null? (cdr numbers))
>          (error "Unable to unindent at top-level."))
>        (set! numbers (cdr numbers))
>        (get-section))
>
>      (lambda args
>        (apply
>          (case (car args)
>            ((get-section) get-section)
>            ((next-section) next-section)
>            ((indent) indent)
>            ((unindent) unindent)
>            (else (error "Unknown method.")))
>          (cdr args)))))
>
> my-section-numberer = #(make-section-numberer)
> my-section-numberer-two = #(make-section-numberer)
>
> \markup \column {
>    #(my-section-numberer 'get-section)
>    #(my-section-numberer 'next-section)
>    #(my-section-numberer 'indent)
>    \italic #(my-section-numberer-two 'get-section)
>    #(my-section-numberer 'indent)
>    #(my-section-numberer 'next-section)
>    \italic #(my-section-numberer-two 'next-section)
>    #(my-section-numberer 'unindent)
>    #(my-section-numberer 'next-section)
>    \italic #(my-section-numberer-two 'next-section)
>    #(my-section-numberer 'unindent)
> }
> %%%%
>
> The principle difference here is that there is make-section-numberer is
> essentially now a constructor.  That means each instance has its own
> "numbers" variable.  The example above uses two instances to demonstrate
> this, with the second italicized for clarity.

Doing some experiments with your code I found no possibility to get from
"1.1.1" directly to "2". Am I too tired?
Likely - or maybe that beer (well, the bottle is empty, new one or bed? LOL)

Inspired by your code I come up with below, happily stealing from yours.
Especially the format-code. `formatĀ“ has far too many options ...

#(define (increase lst idx)
  (if (and (positive? idx) (<= idx (length lst)))
      (let ((tmp-lst (take-right lst idx)))
        (cons (1+ (car tmp-lst)) (cdr tmp-lst)))
      (begin
        (ly:warning
  "idx ~a is not positive or list ~a does not contain enough elements, ignoring"
          idx lst)
        lst)))

#(define (numberer)
 (let ((x (list 1)))
  (define-scheme-function (level arg)((index?) symbol?)
    (case arg
      ((indent) (set! x (cons 1 x)))
      ((increase)
        (if (positive? level)
            (set! x (increase x level))))
      ;; TODO still needed?
      ((reset) (set! x (list 1))))
    (format #f "~{~d~^.~}" (reverse x)))))

foo = #(numberer)
buzz = #(numberer)

\markup
  \box
  \column {
  "foo-test"
  %% To cause the procedure to put out current return-value (without further
  %% changes) any symbol not eq? 'indent 'increase 'reset can be used.
  %% 'start here at the beginning seems to be pretty intuitive.
    \foo #'start
    \foo #'indent
    \foo #'indent
    \foo #1 #'increase
    \foo #'indent
    \underline \line { "buzz" \buzz #'start }
    \foo #2 #'increase
    \foo #2 #'increase
    \underline \line { "buzz" \buzz #'indent }
    \foo #1 #'increase
    \foo #'indent
    \foo #2 #'increase
    \foo #'indent
  }

\markup
  \box
  \column {
  "buzz-test"
    \buzz #'start
    \buzz #1 #'increase
    \buzz #1 #'increase
    \buzz #'indent
    \buzz #'indent
    \buzz #2 #'increase
  }


Also, I've read all of posts of this very interesting thread.
Alas, I'm not a learned programmer. Sometimes I'm missing some basics.
This is one of those cases.
Thus I can't add anything useful to the discussion.

Cheers,
  Harm



reply via email to

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