Reply to topic  [ 7 posts ] 
Mixing wrap_args and closure 
Author Message
Yorick Master

Joined: Wed Jun 01, 2005 11:34 am
Posts: 112
Post Mixing wrap_args and closure
It doesn't seem possible to mix wrap_args and closure. Here's a skeleton of what I'd like to do:

Code:
func example(fixed, args) {
  write, pr1(fixed);
  write, pr1(args);
}
fixed = save(a=1, b=2);
example = closure(example, fixed);
wrap_args, example;

The wrap_args call gives me this error:
ERROR (*main*) wrap_args takes on interpreted function as its argument
(The documentation for wrap_args does state that it's for interpreted functions, so I recognize that this isn't a bug.)

I also tried doing it the other way around:
Code:
func example(args) {
  write, pr1(args);
}
wrap_args, example;
fixed = save(a=1, b=2);
example = closure(example, fixed);

However, the closure effectively cuts off the function from receiving further arguments. "example, 5" gives this error:
ERROR (*main*) too many actual parameters in function call

This is the second time I've come upon wanting this functionality so I thought I'd ask about it in case it's something that could be easily implemented. Would it be feasible to extend wrap_args to work on closures?


Wed Sep 26, 2012 11:47 am
Profile
Yorick Master

Joined: Mon Nov 22, 2004 9:43 am
Posts: 354
Location: Livermore, CA, USA
Post Re: Mixing wrap_args and closure
This is getting way too esoteric, isn't it? A closure is already merely syntactic sugar (shorthand for an object with a single method), and the wrap_args business is intended to be used very, very sparingly for heavily used interactive APIs that just cannot be made as elegant without its introspective features. Nevertheless, it seems to me you can pretty easily get what you want by creating an object with a member function which is a wrap_args function/object, then creating a closure which invokes that member. Instead of the pre-determined argument being an actual argument, of course, you need to access it with the use function. You might even be able to come up with an interpreted metafunction which produces objects of this type, if you insist that you often need them.

Code:
func wrapped_closure(args) {
  n = args(0);
  a = n? array(string, n) : [];
  for (i=1 ; i<=n ; ++i) a(i) = args(-,i);
  use, closure_data;
  closure_data;   /* print fixed closure data */
  a;          /* print positional argument names */
  args(-);  /* print keyword argument names */
}
wrap_args, wrapped_closure;
wrapped_closure = save(wrapped_closure, closure_data="Hello, world!");
wrapped_closure = closure(wrapped_closure, "wrapped_closure");


Results in:

Code:
> wrapped_closure,abc,23,four=4,def
"Hello, world!"
["abc",(nil),"def"]
["four"]


I think this is the semantics you want, except that you need the "use, closure_data" statement in your function body, instead of having it as the first argument to the function. But again, I'm surprised that you often need to go to such lengths to create a good user interface -- it seems very abstract to me.


Sun Sep 30, 2012 3:07 pm
Profile
Yorick Master

Joined: Wed Jun 01, 2005 11:34 am
Posts: 112
Post Re: Mixing wrap_args and closure
munro wrote:
This is getting way too esoteric, isn't it? A closure is already merely syntactic sugar (shorthand for an object with a single method), and the wrap_args business is intended to be used very, very sparingly for heavily used interactive APIs that just cannot be made as elegant without its introspective features.


A closure is also shorthand for a function with a single data object, which makes it handy for letting a function keep internal state. The alternative is to use global names which then might conflict (or which must be made very long to ensure conflicts are avoided).

I find wrap_args useful when I want to write a function that does something "around" something else without having to know much about what that something else is; it allows me to accept arbitrary arguments/keywords that I can then pass through to the something-else function (which likely varies from call to call). It's particularly helpful when I want to be able to extend what that something else is later. I suppose this is still syntactic sugar though, since I could get around it by adding an argument that the user then passed through an oxy object to; but that would make the interface too confusing for end users.

(I do understand that I'm likely pushing the boundaries of how Yorick was intended to be used.)

munro wrote:
Nevertheless, it seems to me you can pretty easily get what you want by creating an object with a member function which is a wrap_args function/object, then creating a closure which invokes that member. Instead of the pre-determined argument being an actual argument, of course, you need to access it with the use function. You might even be able to come up with an interpreted metafunction which produces objects of this type, if you insist that you often need them.


I'm embarrassed to admit that I completely forgot that closure could be used to invoke a member of an object. This sounds like it will address what I want to do very well, thank you!


Mon Oct 01, 2012 4:02 am
Profile
Yorick Master

Joined: Mon Nov 22, 2004 9:43 am
Posts: 354
Location: Livermore, CA, USA
Post Re: Mixing wrap_args and closure
dnagle wrote:
it allows me to accept arbitrary arguments/keywords that I can then pass through to the something-else function (which likely varies from call to call)


There is only very limited support for this in yorick, since there is no way to construct a function call with an arbitrary number of arguments (as there is in python, for example). The intent of wrap_args was to permit you to define an interpreted function with the semantics of the save and restore built-in functions, which use all kinds of information about the names of simple variable reference arguments, allow arbitrary keyword arguments, and so on. This should only be used for functions intended for heavy interactive use (on par with save and restore), as there are always better choices for internal function interfaces called only from other functions.

I don't want to discourage you from using the tools yorick does have, except when I plan to eventually remove a feature. I do not expect either wrap_args or closure to be removed, so feel free to use them as you see fit. Just beware that yorick is a very informal language, and as you move into more and more abstract and introspective corners, you have to understand that there is no theoretical backing for its linguistic constructs. To put it simply, I have no idea what the precise semantics of things like wrap_args or closure or oxy objects might be. For example, what happens if you do "return args;" in a wrap_args function, where 'args" is the wrapped argument list object? All I can say is that it isn't a syntax error, but I haven't the vaguest idea what will happen when the caller attempts to use it. There are many, many syntactically legal constructs of this type which have unknown semantics. Feel free to report such surprises when you find them, but be warned that what you think they should mean may differ irreconcilably from what they actually mean...


Mon Oct 01, 2012 9:03 am
Profile
Yorick Guru

Joined: Wed Nov 24, 2004 12:51 pm
Posts: 97
Location: Observatoire de Lyon (France)
Post Re: Mixing wrap_args and closure
Hi,

Quote:
For example, what happens if you do "return args;" in a wrap_args function, where 'args" is the wrapped argument list object? All I can say is that it isn't a syntax error, but I haven't the vaguest idea what will happen when the caller attempts to use it.

What do you mean? For me, a function like:
Code:
func pack(args) { return args; }
wrap_args, pack;

let me pack anything into an objet that can then be used outside from the 'pack' function. I see no problems for that (unless there is some hidden issue, but it seems to work).

Éric.


Fri Sep 13, 2013 8:51 am
Profile WWW
Yorick Master

Joined: Mon Nov 22, 2004 9:43 am
Posts: 354
Location: Livermore, CA, USA
Post Re: Mixing wrap_args and closure
An oxy object, returned by save(thing1, thing2, ...) is what I intended you to use to store an arbitrary collection. What does your pack(thing1, thing2, ...) give you that save() does not?


Sun Oct 06, 2013 8:07 am
Profile
Yorick Guru

Joined: Wed Nov 24, 2004 12:51 pm
Posts: 97
Location: Observatoire de Lyon (France)
Post Re: Mixing wrap_args and closure
Sorry, I did not mean that the pack() example was superior to using the save() function, I just wrote it to check whether a wrapped argument is usable outside the function which "creates" it and it does. That's all ;-)


Tue Dec 10, 2013 5:02 am
Profile WWW
Display posts from previous:  Sort by  
Reply to topic   [ 7 posts ] 

Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by STSoftware for PTF.