Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access to context inside rust bindings. #34

Closed
Rafagd opened this issue Dec 7, 2017 · 3 comments
Closed

Access to context inside rust bindings. #34

Rafagd opened this issue Dec 7, 2017 · 3 comments

Comments

@Rafagd
Copy link

Rafagd commented Dec 7, 2017

So I have this function in rust bound to ketos that receives a lambda as an argument and calls the lambda in a loop with a different value for its arguments on every run.

Sounds simple enough, but my function can't receive the context as a parameter, so I'm stuck using the interpreter as a global variable.

I understand that functional languages are not supposed to care about the context, but all functions I've found to execute the lambda require me to send the context as a parameter.

What should I do?

@murarth
Copy link
Owner

murarth commented Dec 7, 2017

If this Rust function is being called from Ketos code, it would be best to use the same context for subsequent executions. Perhaps a Rust closure could carry a reference to or a clone of the context.

However, if this isn't possible, you can create a new execution context (using a Scope, which can be extracted from the Lambda struct's weak reference).

@Rafagd
Copy link
Author

Rafagd commented Dec 11, 2017

Ok, so here is a minimal example of what I'm doing. I would love to get rid of INTERP, even if that means ketos_fn! adding the scope as the first argument.

#[macro_use]
extern crate ketos;

static mut INTERP: *mut ketos::Interpreter = { 0 as *mut _ };

fn repeat(n: usize, lambda: &ketos::Value) -> Result<(), ketos::Error>
{
	for i in 0..n {
		let _ = unsafe { (*INTERP).call_value(lambda.clone(), vec![ i.into() ])? };
	}

	Ok(())
}

fn main ()
{
    let mut interp = ketos::Interpreter::new();

    unsafe {
        INTERP = &mut interp as *mut _
    };
    
    ketos_fn! {
        interp.scope() => "rp" =>
            fn repeat(n: usize, lambda: &ketos::Value) -> ()
    }
    
    interp.run_code("(rp 1000 (lambda (i) (println \"~a\" i)))", None).unwrap();
}

@murarth
Copy link
Owner

murarth commented Dec 11, 2017

One alternative would be, rather than using ketos_fn! to create a callable Ketos value, to use Value::new_foreign_fn to wrap a function with the signature fn(&Context, &mut [Value]) -> Result<(), Error>.

You can then use the macro ketos_args! to get (usize, &Value) from the argument slice and execute the given value using the passed &Context.

@murarth murarth closed this as completed Jan 7, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants