如何在Erlang中创建变量arity的功能?

时间:2012-06-10 08:42:25

标签: erlang variadic-functions nonlinear-optimization

我有一个算法可以找到Rn上函数/ n的最小值。我有一个约束流形,以单一立方体图像的形式给出。将奇异立方体内部空间映射到Rn,更重要的是反之亦然,这是非常简单的,可以使用应用于每个坐标的from_R_to_01函数来完成。

所以我想做的是取一些arity的目标函数F,并制作同一个arity的另一个函数,它将是相同的F,除了它的'坐标要从Rn映射到约束流形人。因此,我可以将它赋予我的最小化算法,在Rn中获得一对坐标,然后将它们映射到相同的流形以获得“真实世界”坐标。因此,将非线性编程任务减少到无约束优化。

好吧,回到这个问题。我有这段代码适用于2-ar案例。

minn_man2(F, Man) ->
    OnRn = fun (X, Y) ->  # this is the limiting part
        OnMan = Man( from_R_to_01( X ), from_R_to_01( Y ) ),
        apply( F, OnMan )
    end,
    [X | [ Y | []]] = minn( OnRn ),
    Man( from_R_to_01( X ), from_R_to_01( Y ) ).

如何让它更通用?最难的部分是制作Fs的匿名功能。根本不知道如何做到这一点。

2 个答案:

答案 0 :(得分:4)

您只能通过为它们提供一个列表的参数来模拟具有变量arity的函数(匿名或非匿名)。然后你可以使用apply / 2来评估它。

您的示例可能是(未经过测试或优化),例如

minn_man(F, Man) ->
    OnRn = fun (L) ->  
        OnMan = apply(Man, [from_R_to_01( X ) || X<-L]),
        apply( F, OnMan )
    end,
Man( [from_R_to_01( X ) || X<-minn( OnRn )).

当然,Man也应该以适当的格式返回值。

答案 1 :(得分:1)

想想我已经拥有它了!如果我需要为每个特定的arity明确声明OnRn,我为什么不制作它们。

首先,我在单个“案例MA”声明中为unar和binar Mans手动编写了两个单独的声明。然后我就懒得用python来生成一大堆这些。然后我找了一种eval来让Erlang生成并在运行时评估相应的声明。在这里。像魅力一样。

minn_man(F, Man) ->
    MA = proplists:get_value( arity, erlang:fun_info( Man )),
    R1 = fun (X) -> from_R_to_01(X) end,

    XiStr = string:join(["X" ++ integer_to_list(I) || I <- lists:seq(1, MA)], ", "),
    RiXiStr = string:join(["R1(X" ++ integer_to_list(I) ++ ")" || I <- lists:seq(1, MA)], ", "),
    FunStr = "fun (" ++ XiStr ++ ") -> apply( F, Man(" ++ RiXiStr ++")) end.",

    {ok, Tokens, _} = erl_scan:string(FunStr),
    {ok, [Form]} = erl_parse:parse_exprs(Tokens),
    Binding1 = erl_eval:add_binding('F', F, erl_eval:new_bindings()), 
    Binding2 = erl_eval:add_binding('Man', Man, Binding1), 
    Binding3 = erl_eval:add_binding('R1', R1, Binding2),
    {value, OnRn, _} = erl_eval:expr(Form, Binding3),

    XY = minn( OnRn ),
    apply(Man, lists:map(fun from_R_to_01/1, XY ) ).