scheme set list function

classic Classic list List threaded Threaded
28 messages Options
12
Reply | Threaded
Open this post in threaded view
|

scheme set list function

Gianmaria Lari
I wrote this function

#(define (resetList l) (set! l '()))

that I would like to set a list to an empty list. This is an example of use:

\version "2.21.0"
#(define mylist '(1 2 3))
\markup #(object->string mylist) %this prints (1 2 3)

#(define (resetList l) (set! l '()))
#(resetList mylist)
\markup #(object->string mylist) % this I would like it prints () but it prints (1 2 3)

I think the problem is related to the fact resetList changes mylist locally (sort of) but I have no idea how I can fix it. Any help?

Thank you, g.





_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Thomas Morley-2
Am Sa., 6. Apr. 2019 um 16:11 Uhr schrieb Gianmaria Lari
<[hidden email]>:

>
> I wrote this function
>
> #(define (resetList l) (set! l '()))
>
>
> that I would like to set a list to an empty list. This is an example of use:
>
> \version "2.21.0"
> #(define mylist '(1 2 3))
> \markup #(object->string mylist) %this prints (1 2 3)
>
> #(define (resetList l) (set! l '()))
> #(resetList mylist)
> \markup #(object->string mylist) % this I would like it prints () but it prints (1 2 3)
>
> I think the problem is related to the fact resetList changes mylist locally (sort of) but I have no idea how I can fix it. Any help?
>
> Thank you, g.

One possibility is to use a macro:

#(define-macro (reset-list l) `(set! ,l '()))

Cheers,
  Harm

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Gianmaria Lari
On Sat, 6 Apr 2019 at 16:30, Thomas Morley <[hidden email]> wrote:
Am Sa., 6. Apr. 2019 um 16:11 Uhr schrieb Gianmaria Lari
<[hidden email]>:
>
> I wrote this function
>
> #(define (resetList l) (set! l '()))
>
>
> that I would like to set a list to an empty list. This is an example of use:
>
> \version "2.21.0"
> #(define mylist '(1 2 3))
> \markup #(object->string mylist) %this prints (1 2 3)
>
> #(define (resetList l) (set! l '()))
> #(resetList mylist)
> \markup #(object->string mylist) % this I would like it prints () but it prints (1 2 3)
>
> I think the problem is related to the fact resetList changes mylist locally (sort of) but I have no idea how I can fix it. Any help?
>
> Thank you, g.

One possibility is to use a macro:

#(define-macro (reset-list l) `(set! ,l '()))

Thank you, it works.

 I tried to make the same with the second of these functions:

#(define (allButLast l) (reverse (cdr (reverse l))))
#(define (numberInc l) (append (allButLast l) (list (1+ (last l)))))

 (it simply increments the last integer element of a list). Here it is a code that use it:

\version "2.21.0"
#(define (allButLast l) (reverse (cdr (reverse l))))
#(define (numberInc l) (append (allButLast l) (list (1+ (last l)))))

#(define mylist '(1 2 3))
\markup #(object->string mylist)
#(set! mylist (numberInc mylist))
\markup #(object->string mylist)

And here my try with macro:

#(define-macro (numberInc l) `(set! ,l (append (allButLast l) (list (1+ (last l))))))

and this is a complete code that does not work:

\version "2.21.0"
#(define (allButLast l) (reverse (cdr (reverse l))))
#(define-macro (numberInc l) `(set! ,l (append (allButLast l) (list (1+ (last l))))))


#(define mylist '(1 2 3))
\markup #(object->string mylist)
#(numberInc mylist)
\markup #(object->string mylist)

Does it make sense?
Thank you Harm

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Thomas Morley-2
Am Sa., 6. Apr. 2019 um 17:21 Uhr schrieb Gianmaria Lari
<[hidden email]>:

>
> On Sat, 6 Apr 2019 at 16:30, Thomas Morley <[hidden email]> wrote:
>> One possibility is to use a macro:
>>
>> #(define-macro (reset-list l) `(set! ,l '()))
>
>
> Thank you, it works.
>
>  I tried to make the same with the second of these functions:
>
> #(define (allButLast l) (reverse (cdr (reverse l))))
> #(define (numberInc l) (append (allButLast l) (list (1+ (last l)))))
>
>  (it simply increments the last integer element of a list). Here it is a code that use it:
>
> \version "2.21.0"
> #(define (allButLast l) (reverse (cdr (reverse l))))
> #(define (numberInc l) (append (allButLast l) (list (1+ (last l)))))
>
> #(define mylist '(1 2 3))
> \markup #(object->string mylist)
> #(set! mylist (numberInc mylist))
> \markup #(object->string mylist)
>
>
> And here my try with macro:
>
> #(define-macro (numberInc l) `(set! ,l (append (allButLast l) (list (1+ (last l))))))
>
>
> and this is a complete code that does not work:
>
> \version "2.21.0"
> #(define (allButLast l) (reverse (cdr (reverse l))))
> #(define-macro (numberInc l) `(set! ,l (append (allButLast l) (list (1+ (last l))))))
>
>
> #(define mylist '(1 2 3))
> \markup #(object->string mylist)
> #(numberInc mylist)
> \markup #(object->string mylist)

Well, you need to always unquote the macro's arg(s), here `l´.
Leading to:
#(define-macro (numberInc l)
  `(set! ,l (append (allButLast ,l) (list (1+ (last ,l))))))

Though, I'd think you should rethink whatever you plan, I'm very
skeptic about always resetting a toplevel defined list.
It's too destructive.

Why not let the toplevel list untouched, only changing it locally, like:
#(define (1+last l)
  (if (number? (last l))
      (append (drop-right l 1) (list (1+ (last l))))
      l))

#(define lst '(1.1 2.2 3.3 4.4))

#(display (1+last lst))


For my own projects I need to define such macros averagely every other
5 years ...

Cheers,
  Harm

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Aaron Hill
On 2019-04-06 9:50 am, Thomas Morley wrote:
> Though, I'd think you should rethink whatever you plan, I'm very
> skeptic about always resetting a toplevel defined list.
> It's too destructive.

Also, it is convention to use an exclamation point as a suffix when
naming procedures that may modify the structure of arguments to produce
their results.  This makes it easier for users to know where side
effects might exist.

Consider this:

%%%%
#(define (1+last! lst) (list-set! lst (- (length lst) 1) (1+ (last
lst))))

#(define foo '(1 2 3))
#(1+last! foo)
#(format #t "\nfoo = ~a" foo)
#(1+last! foo)
#(format #t "\nfoo = ~a" foo)
%%%%


-- Aaron Hill

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Gianmaria Lari
Thank you Harm and Aaron!

I tested your solutions;they both work and I think there are pretty clear!! But I think, next days I will try to explain what I'm doing.

Thanks a lot!!!
g.



On Sat, 6 Apr 2019 at 19:09, Aaron Hill <[hidden email]> wrote:
On 2019-04-06 9:50 am, Thomas Morley wrote:
> Though, I'd think you should rethink whatever you plan, I'm very
> skeptic about always resetting a toplevel defined list.
> It's too destructive.

Also, it is convention to use an exclamation point as a suffix when
naming procedures that may modify the structure of arguments to produce
their results.  This makes it easier for users to know where side
effects might exist.

Consider this:

%%%%
#(define (1+last! lst) (list-set! lst (- (length lst) 1) (1+ (last
lst))))

#(define foo '(1 2 3))
#(1+last! foo)
#(format #t "\nfoo = ~a" foo)
#(1+last! foo)
#(format #t "\nfoo = ~a" foo)
%%%%


-- Aaron Hill

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Andrew Bernard
In reply to this post by Gianmaria Lari
Hi Gianmaria,

Can you explain the purpose of nulling out the list?

I am somewhat concerned that there is a misunderstanding you have about Scheme. Scheme procedures are call-by-value. This means the arguments are evaluated and the value then passed to the procedure. The value of the parameter in the calling environment cannot be changed. This is how C and Scheme and many other languages work. [In C you can pass a pointer to alter a variable outside the function. but there is no such thing in Scheme - for good reasons.] It's not call-by-reference.


This is why what you are after can only be done with a macro, which is not a function and operates at the same top level as your list.

I'll stop here as this could turn into a long explanation about Scheme. But I think you are approaching Scheme as though it were a normal procedural programming language, whereas it is far more fluent to use it in a more Lisp like, and functional programming way, if you can, pace the particular requirements of it being embedded in lilypond with guile.

Can I refer you to Kent Dybvig's excellent book in Scheme?


The thing that helped me the most with lilypond was learning Scheme properly and thoroughly. [Not meaning to teach you to suck eggs,]


Andrew


On Sun, 7 Apr 2019 at 01:11, Gianmaria Lari <[hidden email]> wrote:

I think the problem is related to the fact resetList changes mylist locally (sort of) but I have no idea how I can fix it. Any help?
 

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Aaron Hill
On 2019-04-07 6:01 pm, Andrew Bernard wrote:

> I am somewhat concerned that there is a misunderstanding you have about
> Scheme. Scheme procedures are call-by-value. This means the arguments
> are
> evaluated and the value then passed to the procedure. The value of the
> parameter in the calling environment cannot be changed. This is how C
> and
> Scheme and many other languages work. [In C you can pass a pointer to
> alter
> a variable outside the function. but there is no such thing in Scheme -
> for
> good reasons.] It's not call-by-reference.

The way I understand things, that's not entirely true.  Whether a Scheme
interpreter/compiler passes by value or reference is an implementation
detail.  Passing by reference is a convenient optimization to avoid
unnecessary copies and garbage; and near as I can tell this is very
commonly used across many environments.  As such, procedures can have
side effects where the objects that are passed to such procedures may be
modified.  Consider the 1+last! procedure I showed that is not a macro
itself, but it still has the side effect of altering the list.

Perhaps some confusion stems from the distinction between named
variables and objects representing values.  A list called "foo" is
really two things: the actual list and the variable that is bound to
that list.  Passing "foo" to a procedure involves evaluating the
variable to obtain the underlying list, and then this list is given a
new name within the scope of the procedure.  (Let's pretend the argument
to the procedure is "bar".)  This new name is a distinct variable but it
is not a copy of the value.

If you were to (set! bar ...), then you are changing the binding of the
locally-scoped variable "bar" to be something else.  The original list
that was passed in is unaffected because you are simply throwing away
the reference you had to it.  The variable "foo" is similarly unaffected
and still references the original object.

However, if you were to (set! (car bar) ...) or (list-set! bar 0 ...),
then you could in fact alter the first element of the list that was
passed in.  (IIRC, you need SRFI-17 which defines setters for car and
its kin to be able to use the first form.)

That all said, I have often read that the idealistic functional
programmer should in general avoid procedures with side effects.  As
Harm pointed out, such side effects can be dangerous.  So in a way, you
could certainly be justified in pretending the system is pass-by-value
irrespective of the actual implementation.

The better pattern would be to move the set! outside the procedure so
that the caller must be explicit in its application.  That is a
programmer should prefer (set! foo (1+last foo)) over (1+last! foo).  It
is extra typing, but that extra typing makes things clearer and reduces
the likelihood of surprises.  Of note, though, such a preferred usage
technically does not change the original list but rather rebinds "foo"
to a new list that happens to have the desired values.


-- Aaron Hill

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Urs Liska-3
In reply to this post by Andrew Bernard


Am 8. April 2019 03:01:26 MESZ schrieb Andrew Bernard <[hidden email]>:

>Hi Gianmaria,
>
>Can you explain the purpose of nulling out the list?
>
>I am somewhat concerned that there is a misunderstanding you have about
>Scheme. Scheme procedures are call-by-value. This means the arguments
>are
>evaluated and the value then passed to the procedure. The value of the
>parameter in the calling environment cannot be changed. This is how C
>and
>Scheme and many other languages work. [In C you can pass a pointer to
>alter
>a variable outside the function. but there is no such thing in Scheme -
>for
>good reasons.] It's not call-by-reference.
>
>https://en.wikipedia.org/wiki/Evaluation_strategy
>
>This is why what you are after can only be done with a macro, which is
>not
>a function and operates at the same top level as your list.
>
>I'll stop here as this could turn into a long explanation about Scheme.
>But
>I think you are approaching Scheme as though it were a normal
>procedural
>programming language, whereas it is far more fluent to use it in a more
>Lisp like, and functional programming way, if you can, pace the
>particular
>requirements of it being embedded in lilypond with guile.
>
>Can I refer you to Kent Dybvig's excellent book in Scheme?
>
>https://scheme.com/tspl4/

I found that book pretty hard to digest, but indeed working through it (well, at least many parts of it) was the single most important breakthrough for me regarding the understanding of Scheme.

Urs


>
>The thing that helped me the most with lilypond was learning Scheme
>properly and thoroughly. [Not meaning to teach you to suck eggs,]
>
>
>Andrew
>
>
>On Sun, 7 Apr 2019 at 01:11, Gianmaria Lari <[hidden email]>
>wrote:
>
>>
>> I think the problem is related to the fact resetList changes mylist
>> locally (sort of) but I have no idea how I can fix it. Any help?
>>

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Gianmaria Lari
I try to explain what I'm trying to do.

I want some functions helping me to numbering exercise like this:

1
2
3
3.1
3.2
3.3
4
4.1
4.2

etc.
For that I thought to use the following three functions:

#(define (incNumber l) (append (drop-right l 1) (list (1+ (last l)))))
#(define (unindent l) (drop-right l 1))
#(define (indent l) (append l '(1)))

The state of the numbering (the fact that I'm at 1.1 or 3.1.1) is kept in a list that the three functions modify.

In an object oriented approach I would create a class with these three functions and the data structure (list or what else) on which they work on.

In scheme I'm not able to (easily) encapsulate the functions and data in a single element so I thought to create the three functions and pass to them the list on which they have to operate. The functions *need* to change the list. Of course I could do it manually externally to the functions but this increase the risk of introducing bug in the code. The following is just an example of how I solve my problem with the external set! (that I don't think is the right solution for this problem):

\version "2.21.0"
#(define (incNumber l) (append (drop-right l 1) (list (1+ (last l)))))
#(define (unindent l) (drop-right l 1))
#(define (indent l) (append l '(1)))

#(define mylist '(1))
#(display mylist) #(newline) %output: (1)

#(set! mylist (incNumber mylist))
#(display mylist)#(newline) %output: (2)
#(set! mylist (incNumber mylist))
#(display mylist)#(newline) %output: (3)

#(set! mylist (indent mylist))
#(display mylist)#(newline) %output: (3 1)

#(set! mylist (incNumber mylist))
#(display mylist)#(newline) %output: (3 2)

#(set! mylist (incNumber (unindent mylist)))
#(display mylist)#(newline) %output: (4)


I thought that an alternative approach that looks nice to try but it's over-engineering would be to create a single function able to do the work of the three functions according to a parameter. Something like 

#(define (indenter operation l) .....)

if the "operation" argument is "inc" the indenter function has to inc, if the "operation" argument is "indent" the indenter function has to indent etc. I hope I have been clear. 
This solution is nice because encapsulate all - data and structure - and has no problem to modify the list that would be a local persistent data (I don't remember how you call it in scheme).

* *

If I correctly understood, the macro could be another solution. But I have no idea if is the "right" (good) solution (and well, the syntax is to me a bit intimidating).

* *

Finally I tried to use drop-right! and append! in my functions like this: 

#(define (unindent! l) (drop-right! l 1))
#(define (indent! l) (append! l '(1)))

and this works. But I have no idea how to do the same with 

#(define (incNumber l) (append (drop-right l 1) (list (1+ (last l)))))

(I tried to use set! on the left of (append.......) but it doesn't work.
Thank you for your help.
g.

P.S. Another possibility that I didn't yet tried: if the scheme list is a structure made of couple of information, data + pointer,  maybe I could put my information starting from the second element of the list..... sorry if I'm not very clear. I will try and then I will try to explain myself better.

P.P.S 
To Andrew:
Yes Andrew, you're right. Instead of solve my problem by trial and error it would be better to read a good scheme book. I already started and stopped many times...... But I have some books on my (virtual) desktop that I will really read before or later
To Aaron: thank you for having reminded me the convention of exclamation point! I used it in my last code!

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Thomas Morley-2
Am Mo., 8. Apr. 2019 um 10:07 Uhr schrieb Gianmaria Lari
<[hidden email]>:

>
> I try to explain what I'm trying to do.
>
> I want some functions helping me to numbering exercise like this:
>
> 1
> 2
> 3
> 3.1
> 3.2
> 3.3
> 4
> 4.1
> 4.2
>
> etc.

> I thought that an alternative approach that looks nice to try but it's over-engineering would be to create a single function able to do the work of the three functions according to a parameter. Something like
>
>
> #(define (indenter operation l) .....)
>
>
> if the "operation" argument is "inc" the indenter function has to inc, if the "operation" argument is "indent" the indenter function has to indent etc. I hope I have been clear.
> This solution is nice because encapsulate all - data and structure - and has no problem to modify the list that would be a local persistent data (I don't remember how you call it in scheme).
>

How about:

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)))))

\markup \foo #'start
\markup \foo #'indent
\markup \foo #'indent
\markup \foo #'indent
\markup \foo #'increase
\markup \foo #'indent
\markup \foo #'indent
\markup \foo #'indent


\markup \foo #'reset
\markup \foo #'indent
\markup \foo #'increase
\markup \foo #'indent


I'm still not happy with those set-whatever!-thingies. I was beaten
too often. Maybe someone comes up with a better approach.

Cheers,
  Harm

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

David Kastrup
In reply to this post by Aaron Hill
Aaron Hill <[hidden email]> writes:

> On 2019-04-07 6:01 pm, Andrew Bernard wrote:
>> I am somewhat concerned that there is a misunderstanding you have about
>> Scheme. Scheme procedures are call-by-value. This means the
>> arguments are
>> evaluated and the value then passed to the procedure. The value of the
>> parameter in the calling environment cannot be changed. This is how
>> C and
>> Scheme and many other languages work. [In C you can pass a pointer
>> to alter
>> a variable outside the function. but there is no such thing in
>> Scheme -
>> for
>> good reasons.] It's not call-by-reference.
>
> The way I understand things, that's not entirely true.  Whether a
> Scheme interpreter/compiler passes by value or reference is an
> implementation detail.

Absolutely not.

> Passing by reference is a convenient optimization to avoid unnecessary
> copies and garbage; and near as I can tell this is very commonly used
> across many environments.

You are misunderstanding what a Scheme value is.  Scheme values are
often objects, objects have identity comparable with eq? .  If you
modify a passed object, that modifies the original.  Whether a value is
an object with identity (like a cons cell or a vector) is not an
implementation detail but very much well-defined.

> As such, procedures can have side effects where the objects that are
> passed to such procedures may be modified.  Consider the 1+last!
> procedure I showed that is not a macro itself, but it still has the
> side effect of altering the list.

It doesn't have "side effects".  It manipulates the given objects.

> Perhaps some confusion stems from the distinction between named
> variables and objects representing values.  A list called "foo" is
> really two things: the actual list and the variable that is bound to
> that list.  Passing "foo" to a procedure involves evaluating the
> variable to obtain the underlying list, and then this list is given a
> new name within the scope of the procedure.  (Let's pretend the
> argument to the procedure is "bar".)  This new name is a distinct
> variable but it is not a copy of the value.

No.  You are confusing variables (which have static duration and
existence) and bindings.  Your description fits some old forms of Lisp
(like Emacs Lisp without use of lexical bindings) but already Common
Lisp does not generally use dynamic binding for its scoping.

> However, if you were to (set! (car bar) ...) or (list-set! bar 0 ...),
> then you could in fact alter the first element of the list that was
> passed in.  (IIRC, you need SRFI-17 which defines setters for car and
> its kin to be able to use the first form.)

But that's not changing the passed value but changing the passed
_object_, a cons cell.

> That all said, I have often read that the idealistic functional
> programmer should in general avoid procedures with side effects.  As
> Harm pointed out, such side effects can be dangerous.  So in a way,
> you could certainly be justified in pretending the system is
> pass-by-value irrespective of the actual implementation.

It is not a pretense.  Scheme is pass-by-value, period.  Some of those
values may be mutable objects.  If you have an actual call-by-reference
mechanism, it does not depend on the argument type whether or not you
can change the argument.  And you'd be able to, say, change a cons cell
to a vector instead of having to retain the original cons cell with its
identity.

--
David Kastrup

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Aaron Hill
In reply to this post by Thomas Morley-2
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.

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.


-- Aaron Hill

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

David Kastrup
Aaron Hill <[hidden email]> writes:

> 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.

There is no global variable x.  There is a binding, but the scope of the
binding ends with the let.  This binding is anonymous afterwards and has
no name.  You can call functions manipulating the global variable x from
inside of foo and their action is not related to having used the binding
x when defining foo.

--
David Kastrup

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Aaron Hill
On 2019-04-08 4:35 am, David Kastrup wrote:

> Aaron Hill <[hidden email]> writes:
>
>> 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.
>
> There is no global variable x.  There is a binding, but the scope of
> the
> binding ends with the let.  This binding is anonymous afterwards and
> has
> no name.  You can call functions manipulating the global variable x
> from
> inside of foo and their action is not related to having used the
> binding
> x when defining foo.

I didn't say global, I said "global".  The quotes are there
intentionally as I know it is not an actual top-level binding, but it is
effectively no different in practice.

When you use foo there is only one x that matters, and it is shared
amongst all of the uses of the procedure.

This is not inherently a bad thing, if it is understood that such a
construct represents a singleton.  And for something like this section
numbering thing, one could argue a singleton is apropos.

My variation showing an explicit constructor step encapsulates somewhat
better but is ultimately unnecessary if one were only ever going to
instanciate it once.


-- Aaron Hill

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Andrew Bernard
In reply to this post by Aaron Hill
Hi Aaron,

I beg to differ. Here plain and clear from the start of the R5RS Scheme specification is the following:

Arguments to Scheme procedures are always passed by
value, which means that the actual argument expressions
are evaluated before the procedure gains control, whether
the procedure needs the result of the evaluation or not.

I am unable to deduce how the procedure evaluation can therefore be an implementation choice. Call by reference would alter the semantics of Scheme entirely. One of the main strengths of Scheme is that it supports lexical scoping so procedures can't alter variables outside the local scope, unless you resort to using global variables at the top level, but hopefully people no longer program like that.

I've never heard of any Scheme system that uses call by reference, and I would request that you provide evidence for that. If you can my Scheme world will be turned upside down.

I'll do another email about set-car! and list-set! a bit later.


Andrew



On Mon, 8 Apr 2019 at 12:41, Aaron Hill <[hidden email]> wrote:
On 2019-04-07 6:01 pm, Andrew Bernard wrote:
> I am somewhat concerned that there is a misunderstanding you have about
> Scheme. Scheme procedures are call-by-value. This means the arguments
> are
> evaluated and the value then passed to the procedure. The value of the
> parameter in the calling environment cannot be changed. This is how C
> and
> Scheme and many other languages work. [In C you can pass a pointer to
> alter
> a variable outside the function. but there is no such thing in Scheme -
> for
> good reasons.] It's not call-by-reference.

The way I understand things, that's not entirely true.  Whether a Scheme
interpreter/compiler passes by value or reference is an implementation
detail.  Passing by reference is a convenient optimization to avoid
unnecessary copies and garbage; and near as I can tell this is very
commonly used across many environments.  As such, procedures can have
side effects where the objects that are passed to such procedures may be
modified.  Consider the 1+last! procedure I showed that is not a macro
itself, but it still has the side effect of altering the list.



_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Andrew Bernard
In reply to this post by Gianmaria Lari
Hi All,

Here's a very well written post on pointers in Scheme (it doesn't have them, full stop). Wonderful language that it is, you can create something similar for yourself.


Observe that this post also clearly states the Scheme is call by value.

[The matter of lists and set-car! and how lists are pointers to locations is a different topic (I'm getting to it...)]

Andrew



_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Aaron Hill
In reply to this post by David Kastrup
On 2019-04-08 4:08 am, David Kastrup wrote:
> Aaron Hill <[hidden email]> writes:
>> As such, procedures can have side effects where the objects that are
>> passed to such procedures may be modified.  Consider the 1+last!
>> procedure I showed that is not a macro itself, but it still has the
>> side effect of altering the list.
>
> It doesn't have "side effects".  It manipulates the given objects.

Yet that is the very definition of a side effect [1].

[1]: https://en.wikipedia.org/wiki/Side_effect_(computer_science)

To modify such an object which is outside your local scope falls into
that category.  Remember a side effect is not automatically an
"unintended" side effect which is quite dangerous.

To increment a value is to effect a change on the system.  And if that
state affected is outside local scope, then it is by definition a side
effect.  And such a procedure would *not* be a pure function.

>> However, if you were to (set! (car bar) ...) or (list-set! bar 0 ...),
>> then you could in fact alter the first element of the list that was
>> passed in.  (IIRC, you need SRFI-17 which defines setters for car and
>> its kin to be able to use the first form.)
>
> But that's not changing the passed value but changing the passed
> _object_, a cons cell.
>
>> That all said, I have often read that the idealistic functional
>> programmer should in general avoid procedures with side effects.  As
>> Harm pointed out, such side effects can be dangerous.  So in a way,
>> you could certainly be justified in pretending the system is
>> pass-by-value irrespective of the actual implementation.
>
> It is not a pretense.  Scheme is pass-by-value, period.  Some of those
> values may be mutable objects.  If you have an actual call-by-reference
> mechanism, it does not depend on the argument type whether or not you
> can change the argument.  And you'd be able to, say, change a cons cell
> to a vector instead of having to retain the original cons cell with its
> identity.

Okay, I think I see where I have gone wrong in my thinking.  I must be
conflating pass-by-value and pass-by-copy.

In C, if you were to pass an integer to a function, that function gets a
copy of the value on the stack.  You can of course modify it, but that
would have no ability to effect a change to the original variable in the
caller's scope.

Now let us pass a pointer to an integer to a function.  The function
still gets a copy but this time it is of the memory address, not the
data to which is points.  There is no means to effect any change to the
original pointer passed in; but since both the caller's pointer and the
function's pointer point to the same thing, they are able to collaborate
and see each other's changes.

This seems to be a matter of semantics.  A pointer is itself just a
number, a value in its own right.  And to pass a pointer is to
pass-by-value.  But if our intention is that we want to pass an object
via its memory address, then we are passing-by-reference.


-- Aaron Hill

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Aaron Hill
In reply to this post by Andrew Bernard
On 2019-04-08 5:31 am, Andrew Bernard wrote:
> Hi All,
>
> Here's a very well written post on pointers in Scheme (it doesn't have
> them, full stop). Wonderful language that it is, you can create
> something
> similar for yourself.

We do not have access to pointers in the Scheme language, as it is
intended to be abstract from such a lower-level detail.  But that
doesn't mean there are no pointers behind the scenes.  An
interpreter/compiler is free to implement the language however it sees
fit.  If you were writing in C, then you are almost certainly going to
be leveraging pointers.

The point here is that some form of indirection must be occurring, since
it is possible to pass in a list to a procedure and have that list be
modified.  Yes, we are not modifying the variable in the caller's scope;
but we are modifying what it *refers* to.  Hence, why I had considered
it pass-by-reference.

Obviously, I am in error with my terminology.


-- Aaron Hill

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
Reply | Threaded
Open this post in threaded view
|

Re: scheme set list function

Carl Sorensen-3
In reply to this post by Thomas Morley-2


On 4/8/19, 3:48 AM, "Thomas Morley" <[hidden email]> wrote:

    Am Mo., 8. Apr. 2019 um 10:07 Uhr schrieb Gianmaria Lari
    <[hidden email]>:
    >
    > I try to explain what I'm trying to do.
    >
    > I want some functions helping me to numbering exercise like this:
    >
    > 1
    > 2
    > 3
    > 3.1
    > 3.2
    > 3.3
    > 4
    > 4.1
    > 4.2
    >
    > etc.
   
    > I thought that an alternative approach that looks nice to try but it's over-engineering would be to create a single function able to do the work of the three functions according to a parameter. Something like
    >
    >
    > #(define (indenter operation l) .....)
    >
    >
    > if the "operation" argument is "inc" the indenter function has to inc, if the "operation" argument is "indent" the indenter function has to indent etc. I hope I have been clear.
    > This solution is nice because encapsulate all - data and structure - and has no problem to modify the list that would be a local persistent data (I don't remember how you call it in scheme).
    >
   
    How about:
   
    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)))))
   
    \markup \foo #'start
    \markup \foo #'indent
    \markup \foo #'indent
    \markup \foo #'indent
    \markup \foo #'increase
    \markup \foo #'indent
    \markup \foo #'indent
    \markup \foo #'indent
   
   
    \markup \foo #'reset
    \markup \foo #'indent
    \markup \foo #'increase
    \markup \foo #'indent
   
   
    I'm still not happy with those set-whatever!-thingies. I was beaten
    too often. Maybe someone comes up with a better approach.

This is pretty consistent with the way objects with local state are implemented in Structure and Interpretation of Computer Programs.

See https://web.mit.edu/alexmv/6.037/sicp.pdf and check out the bank account examples in section 3.1

But you haven't implemented 'start in this code, have you?    It's a default no-op.  You could start your indentation by using any symbol that is not 'reset, 'increase, or 'indent, iIUC.


HTH,

Carl
 

_______________________________________________
lilypond-user mailing list
[hidden email]
https://lists.gnu.org/mailman/listinfo/lilypond-user
12