我试过这个:
cl_object f(long nargs,...) { std::cout << nargs << std::endl; std::cout << "has value?" << std::endl; cl_print(1,cl_boundp(c_string_to_object("HI"))); std::cout << "\ndone" << std::endl; return Cnil; } auto closure = ecl_make_cclosure_va(f,c_string_to_object("((HI . 2))"),Cnil); ecl_defparameter(c_string_to_object("F"),closure);
这使得函数f在lisp中可以用(funcall f)调用,但是cl_boundp总是在f的主体内返回nil.如何构造ecl_make_cclosure_va的env(environment)参数,以便本机代码可以读取闭包中的值?我认为这只是一个alist,但显然不是,我没有找到在Google上构建一个的例子.
解决方法
更容易接近
我已经根据ECL接口概述了这一点,但它可能主要通过FFI接口完成,以实现更清晰,更便携的方法.
码:
// defined here as a non-varargs function - you'll need to change it slightly cl_object f(cl_object hi,cl_object func_param1,cl_object_fund_param2) { // note you can pass hi back to lisp fairly easily cl_object name = ecl_make_symbol("do-something-useful","CL-USER"); cl_funcall(2,name,hi); // some other stuff }
>换行函数使其可以通过lisp调用(ecl_def_c_function?)
>用Lisp包裹封口
码:
cl_object wrapped_c_function = cl_safe_eval(c_string_to_object( "(let ((hi 2)) #'(lambda (x y) (your-c-function hi x y)))"),Cnil,Cnil);
原始答案:
这是一个稍微长的答案,说“不容易”但是:
理解ecl做什么的最简单方法是使用它来编译一个简单的脚本到C(ecl -c< filename.c> -compile< filename.lisp>).这是一个简单的lisp,它生成一个带有可变参数列表的闭包
(defun make-closure-function (x y) #'(lambda (&rest arguments) (apply '+ (append (list x y) arguments)))) (defun main () (let ((f (make-closure-function 1 2))) (print (funcall f 3))) (format t "~%")) (main)
/* function deFinition for MAKE-CLOSURE-FUNCTION */ /* optimize speed 3,debug 0,space 0,safety 2 */ static cl_object L2make_closure_function(cl_object v1x,cl_object v2y) { cl_object env0; cl_object CLV0,CLV1; const cl_env_ptr cl_env_copy = ecl_process_env(); cl_object value0; ecl_cs_check(cl_env_copy,value0); { env0 = ECL_NIL; CLV0 = env0 = CONS(v1x,env0); /* X */ CLV1 = env0 = CONS(v2y,env0); /* Y */ { cl_object v3; v3 = ecl_make_cclosure_va((cl_objectfn)LC1__g0,env0,Cblock); value0 = v3; cl_env_copy->nvalues = 1; return value0; } } } /* closure G0 */ /* optimize speed 3,safety 2 */ static cl_object LC1__g0(cl_narg narg,...) { cl_object T0,T1; cl_object CLV0,CLV1; const cl_env_ptr cl_env_copy = ecl_process_env(); cl_object env0 = cl_env_copy->function->cclosure.env; cl_object value0; ecl_cs_check(cl_env_copy,value0); /* Scanning closure data ... */ CLV1 = env0; /* Y */ CLV0 = _ecl_cdr(CLV1); { /* ... closure scanning finished */ { cl_object v1arguments; ecl_va_list args; ecl_va_start(args,narg,0); v1arguments = cl_grab_rest_args(args); ecl_va_end(args); T0 = cl_list(2,ECL_CONS_CAR(CLV0),ECL_CONS_CAR(CLV1)); T1 = ecl_append(T0,v1arguments); value0 = cl_apply(2,ECL_SYM("+",14),T1); return value0; } } } /* function deFinition for MAIN */ /* optimize speed 3,safety 2 */ static cl_object L3main() { cl_object T0; const cl_env_ptr cl_env_copy = ecl_process_env(); cl_object value0; ecl_cs_check(cl_env_copy,value0); { TTL: { cl_object v1f; v1f = L2make_closure_function(ecl_make_fixnum(1),ecl_make_fixnum(2)); T0 = ecl_function_dispatch(cl_env_copy,v1f)(1,ecl_make_fixnum(3)); ecl_print(T0,ECL_NIL); } value0 = cl_format(2,ECL_T,VV[1]); return value0; } }
它在make_closure_function中创建env0,并使其附加x和y列表.然后它调用ecl_make_cclosure_va.在LC1_g0(lambda的包装)中,它使用cl_object env0 = cl_env_copy-> function-> cclosure.env;来访问环境.
请注意,访问环境中的值是因为它知道顺序,而不是能够按名称获取它们.
您基本上必须复制此机制来访问c函数中的闭包变量(尽管您可以生成一个以模式方便的方式存储值的环境(例如(HI 2)列表).
您最好的选择可能是使用ecl_bds_bind将来自环境的位绑定为特殊变量(参见http://ecls.sourceforge.net/new-manual/re04.html).如果你这样做,那么我想你可以使用HI.虽然要注意它是动态的而不是词法上的约束.
虽然这是很多工作!这真的不是“面向用户的界面”.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。