unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Best way to call a user defined hook (written in guile) from C when the hook need plenty parameters
@ 2010-07-05  8:56 rixed
  2010-07-05  9:57 ` Thien-Thi Nguyen
  2010-07-05 20:18 ` Neil Jerram
  0 siblings, 2 replies; 6+ messages in thread
From: rixed @ 2010-07-05  8:56 UTC (permalink / raw)
  To: guile-user

Hello !

Frequently, our C program computes a set of approximately 50 values that it wants
to make accessible for a user defined call back so that the user can choose to
print some of these values (if some condition is met for instance).

I first thought to make some C functions accessible that would return the
values (one C getter per value), and have the C scheme procedure call these
C functions for the values it's interested in. But the problem is that it's
a little verbose (both in C and in scheme due to the required parenthesis).

I then though of binding the values to global variables that the user callback
would use but ruled this out because I was afraid this solution would be slow.

Then I wanted to pass the values as regular parameters, but I don't want to impose
the user to define his function with 50 parameters.

So finally we came up with something like this :

The user enter merely a list of the values he wants (in a "configuration" file) :

(define user-fields `(foo bar (+ baz foo) (if (> foo bar) 1 2)))

And then in C we evaluate :

(define (hook-helper %s) (lambda () #\t))

where %s is the long list of parameters (foo bar baz...) that's inserted by the C program.
And :

(define (hook . args) (local-eval (cons print-user-fields user-fields) (procedure-environment (apply hook-helper args))))

So the user entry is minimal and we can, for each set of values, apply the hook
function to the values (which is I think one of the fastest way to make available some
a set of named values to scheme).

The downside is : the above scheme line looks like black magic.

Can anyone suggest a better way to do this ?





^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Best way to call a user defined hook (written in guile) from C when the hook need plenty parameters
  2010-07-05  8:56 Best way to call a user defined hook (written in guile) from C when the hook need plenty parameters rixed
@ 2010-07-05  9:57 ` Thien-Thi Nguyen
  2010-07-07 14:33   ` Cedric Cellier
  2010-07-05 20:18 ` Neil Jerram
  1 sibling, 1 reply; 6+ messages in thread
From: Thien-Thi Nguyen @ 2010-07-05  9:57 UTC (permalink / raw)
  To: rixed; +Cc: guile-user

() rixed@happyleptic.org
() Mon, 5 Jul 2010 10:56:36 +0200

   Can anyone suggest a better way to do this ?

For "a set of named values", you can use an association list.

If the paren verbosity is off-putting, a common way is to take/show
plists externally (minimal (one) set of parens).  So, user sees:

  (k1 v1 k2 v2 ...)

which is not so threatening, but you manipulate internally:
 
  ((k1 . v1)
   (k2 . v2)
   ...)

This requires a transform, but you do that anyway
(as part of validating the user input), right?

All this presumes that there is no need to specify all keys all the time.
(Re-reading your post, perhaps i am misunderstanding the problem question.)

If the problem really is: how to avoid unwieldy argument lists, the answer
is still "use an association list", but pass to the user a procedure that
encapsulates it.  For example:

(define (query-proc alist)
  "Encapsulate ALIST; return a procedure to query it."
  (lambda (key)
    (assoc-ref alist key)))

(define ALIST '((k1 . v1) (k2 . v2)))
(define QUERY (query-proc ALIST))

;; On the user side:

(define (monitor query)
  (for-each (lambda (key)
              (simple-format #t "k: ~S~%v: ~S~%" key (query key)))
            '(k1 k2)))

This example is read-only; if you want ‘monitor’ to be able to munge
you can change ‘query-proc’ to perhaps ‘query/munge-proc’:

(define (query/munge-proc alist)
  "Encapsulate ALIST; return a procedure query/munge it."
  (lambda (key . newval)
    (if (null? newval)
        (assoc-ref alist key)
        (set! alist (assoc-set! alist key (car newval))))))
        
(It all depends on how much you trust the users.  ;-)

thi



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Best way to call a user defined hook (written in guile) from C when the hook need plenty parameters
  2010-07-05  8:56 Best way to call a user defined hook (written in guile) from C when the hook need plenty parameters rixed
  2010-07-05  9:57 ` Thien-Thi Nguyen
@ 2010-07-05 20:18 ` Neil Jerram
  2010-07-06 11:22   ` Cedric Cellier
  2010-07-08 19:51   ` Andy Wingo
  1 sibling, 2 replies; 6+ messages in thread
From: Neil Jerram @ 2010-07-05 20:18 UTC (permalink / raw)
  To: rixed; +Cc: guile-user

rixed@happyleptic.org writes:

> (define (hook-helper %s) (lambda () #\t))
>
> where %s is the long list of parameters (foo bar baz...) that's inserted by the C program.
> And :
>
> (define (hook . args) (local-eval (cons print-user-fields user-fields) (procedure-environment (apply hook-helper args))))

Using local-eval and procedure-environment like this won't work in Guile
1.9/2.0, I believe.

But you could get a similar effect - which I think will still work in
1.9/2.0 - by creating a module, defining values in it, and then
evaluating in that module.  (In Guile, module == top level environment.)

(Note that the bindings in a module are conceptually similar to an alist,
so this is actually not so different from what Thien-Thi suggested.)

To create a module, in Scheme:

(define-module (xxx))

Then your C code would access that using

SCM module = scm_c_resolve_module ("xxx");

and define each value in it using

scm_c_module_define (module, name, value);

and finally evaluate in that module using

scm_c_eval_string_in_module (expression, module);

It would also seem (at least to me) a bit less magical to define the
user-fields as a procedure, e.g.:

(define (calc-user-fields)
  (list foo
        bar
        (+ baz foo)
        (if (> foo bar) 1 2)))

and then the "expression" above would be "(calc-user-fields)".

All completely untested, of course! :-)

Regards,
     Neil



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Best way to call a user defined hook (written in guile) from C when the hook need plenty parameters
  2010-07-05 20:18 ` Neil Jerram
@ 2010-07-06 11:22   ` Cedric Cellier
  2010-07-08 19:51   ` Andy Wingo
  1 sibling, 0 replies; 6+ messages in thread
From: Cedric Cellier @ 2010-07-06 11:22 UTC (permalink / raw)
  To: guile-user

-[ Mon, Jul 05, 2010 at 09:18:30PM +0100, Neil Jerram ]----
> But you could get a similar effect - which I think will still work in
> 1.9/2.0 - by creating a module, defining values in it, and then
> evaluating in that module.  (In Guile, module == top level
> environment.)

I was trying to avoid binding values to variables because I believe it
would be too slow. I think, having performed no measurment, that passing
the values as function parameters is much faster than manualy binding
these values to an environment. But maybe I'm wrong, and function
parameters are actualy implemented in a way similar to an alist ?





^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Best way to call a user defined hook (written in guile) from C when the hook need plenty parameters
  2010-07-05  9:57 ` Thien-Thi Nguyen
@ 2010-07-07 14:33   ` Cedric Cellier
  0 siblings, 0 replies; 6+ messages in thread
From: Cedric Cellier @ 2010-07-07 14:33 UTC (permalink / raw)
  To: guile-user

(resend since previous mail was not delivered)

First, let's give more details about what we are trying to implement.
The main C program is continuously measuring some realtime evolving
values, and periodically (lets say every 30 seconds) it must dump all
measurements in a CSV file. As there are many such measurements to dump
(say several tens of thousands) the dump itself must be reasonably fast
so that the measurement are not halted for too long.

Now, the C program measure an awful lot of things, and we are not always
interested in every value, and we would like to have the ability to
perform some hot reconfiguration of the CSV format in order to :

- skip entries when the measurement looks suspicious
- apply some numerical operations on individual values (for instance,
  dump the sum of two values instead of each one individually)
- reorder the fields
- etc...

That's where guile enter the stage.

Given a list of field names, the user enter (in a configuration file
or live on a socket) the list of fields (or any other scheme expressions)
he wants in the CSV file.

Every time the program wants to dump its values into a CSV file it will
loop over all the measurement and call a guile hook that must print the
required fields.

And by user I mean another in-house program so this configuration must
not be monkey proof. :)

Hope it's clearer now.

> For "a set of named values", you can use an association list.

I though of this, but I'm afraid the linear lookups in the alist would 
take too much time (we want to call the hook that write a CSV line
approx 50k times in a loop, for every dump, so getting the value of foo
should take a constant (small) time). I think (but haven't checked yet)
that the binding between arguments values and argument names is much
faster than that, since basically arguments are accessed directly by
number (the fact that argument foo is the nth argument is known at
"compile" time).

Thank you very much for your suggestion that I'm now going to study more
closely :-)




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Best way to call a user defined hook (written in guile) from C when the hook need plenty parameters
  2010-07-05 20:18 ` Neil Jerram
  2010-07-06 11:22   ` Cedric Cellier
@ 2010-07-08 19:51   ` Andy Wingo
  1 sibling, 0 replies; 6+ messages in thread
From: Andy Wingo @ 2010-07-08 19:51 UTC (permalink / raw)
  To: Neil Jerram; +Cc: guile-user

On Mon 05 Jul 2010 21:18, Neil Jerram <neil@ossau.uklinux.net> writes:

> rixed@happyleptic.org writes:
>
>> (define (hook-helper %s) (lambda () #\t))
>>
>> where %s is the long list of parameters (foo bar baz...) that's inserted by the C program.
>> And :
>>
>> (define (hook . args) (local-eval (cons print-user-fields user-fields) (procedure-environment (apply hook-helper args))))
>
> Using local-eval and procedure-environment like this won't work in Guile
> 1.9/2.0, I believe.
>
> But you could get a similar effect - which I think will still work in
> 1.9/2.0 - by creating a module, defining values in it, and then
> evaluating in that module.  (In Guile, module == top level
> environment.)

Yes, I think this is the best option, too. FWIW anyway :)

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-07-08 19:51 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-07-05  8:56 Best way to call a user defined hook (written in guile) from C when the hook need plenty parameters rixed
2010-07-05  9:57 ` Thien-Thi Nguyen
2010-07-07 14:33   ` Cedric Cellier
2010-07-05 20:18 ` Neil Jerram
2010-07-06 11:22   ` Cedric Cellier
2010-07-08 19:51   ` Andy Wingo

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