unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
From: Damien Mattei <damien.mattei@gmail.com>
To: mikael@djurfeldt.com
Cc: Nate Rosenbloom <nate.rosenbloom@gmail.com>,
	guile-user <guile-user@gnu.org>
Subject: Re: access slot of a class
Date: Tue, 21 Nov 2023 19:10:01 +0100	[thread overview]
Message-ID: <CADEOadfNscPaFBKU=DTaZYJta3RfFzb+Vr9Eo=N+xNk1SrJ8XQ@mail.gmail.com> (raw)
In-Reply-To: <CAA2Xvw+spFWb1CAwaErj95r+871g-mFjbJnB9-M7=qAzgW_PPQ@mail.gmail.com>

yes , and the solution i found is to pass the object to the method as
argument,
then assigning slot to local variables with accessors in the method and the
source code from Racket or Kawa. Original code was from Python and i had a
bit the same problem, not that slot are not accessible from method, they
are in Python, but you have to use self.v to access v and that is boring in
math expression, so i copy like that v=self.v and then i use v, after
computation, of course i have to update self.v with self.v=v. There is no
other solution in Python.

Example:
class ReseauRetroPropagation():

    def __init__(self,nc=[2,3,1], nbiter=3, ηₛ=1.0 , #ηₑ=0.0001 ,
                 activation_function_hidden_layer=tanh,
                 activation_function_output_layer=tanh,
                 activation_function_hidden_layer_derivative=der_tanh,
                 activation_function_output_layer_derivative=der_tanh):


        lnc = len(nc) # the total of all layer including input, output and
hidden layers

        self.z = [ [0] * n for n in nc ] # les entrées concrètes seront
fournies avec la méthode accepte
        self.z̃ = [ [0] * n for n in nc ] # z̃[0] is not used as z[0] is x,
the initial data


....

 def accepte_et_propage(self,x):         # on entre des entrées et on les
propage

        # note: i just reference the variables for code readness (hide all
the self keyword)
        z = self.z
        z̃ = self.z̃
        M = self.M

        if len(x) != len(z[0]):
            raise ValueError("Mauvais nombre d'entrées !")

        #z[0] = x       # on ne touche pas au biais
        self.z[0] = z[0] = x

        n = len(z)

        # hidden layers
        for i in range(n-2) :

            # create a list with 1 in front for the bias coefficient
            z_1 = [1] + z[i]

            z̃[i+1] = M[i] * z_1 # z̃ = matrix * iterable (list here) ,
return a list

            z[i+1] =
list(map(self.activation_function_hidden_layer,z̃[i+1]))

            # update the variable when necessary
            self.z[i+1] = z[i+1]
            self.z̃[i+1] = z̃[i+1]

this is consuming processor cycles of course but the coding is more easy.

finally the solution in Guile looks like that:

(define-class ReseauRetroPropagation ()

  (nbiter #:init-value 3 #:init-keyword #:nbiter)
  (activation_function_hidden_layer #:init-keyword
#:activation_function_hidden_layer)
  (activation_function_output_layer #:init-keyword
#:activation_function_output_layer)
  (activation_function_hidden_layer_derivative #:init-keyword
#:activation_function_hidden_layer_derivative)
  (activation_function_output_layer_derivative #:init-keyword
#:activation_function_output_layer_derivative)

  (ηₛ #:init-value 1.0 #:init-keyword #:ηₛ)

  (z #:getter nbp-get-z #:setter nbp-set-z!)


....


(define (*init* nc nbp)

(display "*init* : nc=") (display nc) (newline)

{lnc <+ (vector-length nc)}

(define (make-vector-zero lg) (make-vector lg 0))

{z <+ (nbp-get-z nbp)}

{z <- (vector-map make-vector-zero nc)}
    (display "z=") (display z) (newline)


(nbp-set-z! nbp z)
...

) ; end method *init*

Damien


On Tue, Nov 21, 2023 at 11:31 AM Mikael Djurfeldt <mikael@djurfeldt.com>
wrote:

> OK, now I see what you are asking. You want the slots to be available as
> local variables in the lexical scope of the method. The answer is that that
> is not possible "out of the box". I guess it *could* be made available
> through some contortionist coding using a combination of GOOPS and the
> syntax-case macro system, but it goes against the design of GOOPS and CLOS.
> There are macro systems where the class definition provides a lexical scope
> and there are macro systems based on generic functions. It's two different
> takes on object orientation.
>
> (Note though regarding the citation about a method not being formally
> associated with a single class: In the case of accessor methods, which take
> a single argument, they are in a sense associated with a single class.)
>
> On Tue, Nov 21, 2023 at 9:19 AM Damien Mattei <damien.mattei@gmail.com>
> wrote:
>
>> that is interesting answer about guile's features i did not know ,
>> it is related with code i'm writing that instead of fetching the value
>> modify it using the fetch syntax in Scheme+ but my question was just
>> about how to have a class method in a class that can set! the value of
>> a slot. This does nt seem to be available in Guile because "A method
>> is not formally associated with any single class (as it is in many
>> other object oriented languages)" [0].
>>
>> i will explain the problem more in my answer to Mikael and you, i just
>> wanted to be able to create a class method that can access the slot
>> directly , more than in the example [2] :
>>
>> (define-class <my-complex> (<number>)
>>    (r #:init-value 0 #:accessor real-part #:init-keyword #:r)
>>    (i #:init-value 0 #:accessor imag-part #:init-keyword #:i))
>>
>> (set! (real-part c) new-value)
>>
>> in othe Scheme i can do simply:
>>
>> (set! r new-value)
>>
>> for example in Kawa:
>>
>> (define-simple-class ReseauRetroPropagation ()
>>
>>   (nbiter init-value: 3)
>>   (activation_function_hidden_layer)
>>   (activation_function_output_layer)
>>   (activation_function_hidden_layer_derivative)
>>   (activation_function_output_layer_derivative)
>>
>>   (ηₛ 1.0)
>>
>>   (z)
>>   (z̃)
>>
>>   (M)
>>
>>   (ᐁ)
>>
>>   (error 0)
>>
>>   ((*init* nc nbiter0 ηₛ0 activation_function_hidden_layer0
>>                      activation_function_output_layer0
>>               activation_function_hidden_layer_derivative0
>>               activation_function_output_layer_derivative0)
>>
>>    (display "*init* : nc=") (display nc) (newline)
>>    {nbiter <- nbiter0}
>>    {ηₛ <- ηₛ0}
>>
>> ...
>>
>> or in Racket :
>>
>> (define ReseauRetroPropagation
>>
>>   (class object%
>>
>>      (super-new)
>>
>>      ; this is the initialisation parameters
>>      (init-field (nc #(2 3 1)) ;; on crée le tableau des couches du réseau
>>                     (nbiter 10000)
>>                     (ηₛ 1.0)
>>              (activation_function_hidden_layer tanh)
>>              (activation_function_output_layer tanh)
>>              (activation_function_hidden_layer_derivative der_tanh)
>>              (activation_function_output_layer_derivative der_tanh))
>>
>>      {lnc <+ (vector-length nc)}
>>
>>      ; les entrées concrètes seront fournies avec la méthode accepte
>>      ;; (field (z (vector-ec (: i (vector-length nc)) (make-vector
>> {nc[i]} 0))))
>>      ;;(field (z (vector-ec (:vector lg nc)
>>     ;;              (make-vector lg 0))))
>>      (field (z (vector-map (lambda (lg) (make-vector lg 0))
>>                    nc)))
>>
>>      ;; (field (z (for/vector ([lg nc])
>>      ;;                (make-vector lg 0))))
>>
>>      (display "z=") (display z) (newline)
>>
>>
>>      ; z̃[0] is not used as z[0] is x, the initial data
>>      ;;(field (z̃ (vector-ec (:vector lg nc)
>>         ;;          (make-vector lg 0))))
>>      (field (z̃ (vector-map (lambda (lg) (make-vector lg 0))
>>                    nc)))
>>
>>
>>      (display "z̃=") (display z̃) (newline)
>>
>>
>>      {M <+ (vector-ec (: n {lnc - 1}) ; vectors by eager comprehension
>> (SRFI 42)
>>               create-matrix-vect-by-function(uniform-dummy nc[n + 1]
>> {nc[n] + 1}))} ;; Matrix-vect
>>
>>      ;(field (M (vector-ec (: n {lnc - 1}) ; vectors by eager
>> comprehension (SRFI 42)
>>      ;          (create-matrix-vect-by-function uniform-dummy {nc[n +
>> 1]} {nc[n] + 1})))) ;; Matrix-vect
>>
>>
>>      (display "M=") (display M) (newline)
>>
>>      (field (ᐁ (for/vector ([lg nc])
>>                    (make-vector lg 0))))
>>
>>
>>      (display "ᐁ=") (display ᐁ) (newline)
>>
>>      (display "nbiter=") (display nbiter) (newline)
>>
>>      (field (error 0))
>>
>>
>>      ; forward propagation
>>
>>          ; z_* sans le coef. 1 constant pour le bias
>>      (define (accepte_et_propage x) ; on entre des entrées et on les
>> propage
>>
>>         (when {vector-length(x) ≠ vector-length(z[0])}
>>           (display "Mauvais nombre d'entrées !") (newline)
>>           (exit #f))
>>
>>         {z[0] <- x} ; on ne touche pas au biais
>>
>> in those 2 example z is a slot (or field in Racket) of the class
>> ReseauRetroPropagation that can directly be accessed from a class
>> method without using the accessors (getter and setter)
>>
>> Regards,
>> Damien
>>
>>
>>
>>
>> [0] 8.6 Methods and Generic Functions
>>
>> https://www.gnu.org/software/guile/manual/html_node/Methods-and-Generic-Functions.html
>>
>> [2] 8.5  Illustrating Slot Description:
>>
>> https://www.gnu.org/software/guile/manual/html_node/Slot-Description-Example.html
>>
>> On Mon, Nov 20, 2023 at 11:43 PM Nate Rosenbloom
>> <nate.rosenbloom@gmail.com> wrote:
>> >>
>> >> is there a way to access a slot of a class like other variable with
>> set! ,
>> >> Racket,Kawa allow that, but it does not seem to be the case in Guile.
>> >
>> >
>> > Hello Damien:
>> > Does 'generalized set'[0] do what you want?
>> > You can create accessor procedures that have an attached setter -
>> >
>> > Or were you speaking specifically about class slots? In which case it
>> looks like the accessor can be used in in set!: [2]
>> > Thanks,
>> > Nate
>> > [0] 7.5.14 sfri 17 Generalized set!:
>> https://www.gnu.org/software/guile/manual/html_node/SRFI_002d17.html
>> > [1] 6.7.8 Procedures with Setters:
>> https://www.gnu.org/software/guile/manual/html_node/Procedures-with-Setters.html
>> > [2] 8.5  Illustrating Slot Description:
>> https://www.gnu.org/software/guile/manual/html_node/Slot-Description-Example.html
>> >
>>
>


      parent reply	other threads:[~2023-11-21 18:10 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-11-20 21:32 access slot of a class Damien Mattei
2023-11-20 23:27 ` Mikael Djurfeldt
     [not found] ` <CABESxg=NP7LJepcAG-z21f13tVup0NL0iG=4ae+dCADNf+Xpsg@mail.gmail.com>
2023-11-21  8:19   ` Damien Mattei
2023-11-21  8:21     ` Damien Mattei
2023-11-21 10:31     ` Mikael Djurfeldt
2023-11-21 11:49       ` Mikael Djurfeldt
2023-11-21 18:10       ` Damien Mattei [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CADEOadfNscPaFBKU=DTaZYJta3RfFzb+Vr9Eo=N+xNk1SrJ8XQ@mail.gmail.com' \
    --to=damien.mattei@gmail.com \
    --cc=guile-user@gnu.org \
    --cc=mikael@djurfeldt.com \
    --cc=nate.rosenbloom@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).