How to dynamically generate functions in Lua? - function

If I have a table {field1=1,field2=0} (0: ascending order, 1: descending order)
I want to get a function:
function(x,y)
return x.field1 < y.field1 --there 0:'<',1:'>='
end
field1 in the table and the sorting rule can be injected in the function.
How to generate this code dynamically?

Let's talk about more than just the code generation approach! As in the question, consider the need of a function:
function (x, y)
return x.field1 --[[ < or >= ]] y.field1
end
For the sake of the examples assume that we have global variables:
FIRST = {field1 = 3}
SECOND = {field1 = 5}
Branching
The simplest solution (perhaps also the most typical?) that comes to my mind is a verbose if:
function foo (x, y, o)
if o == nil or o == "asc" then
return x.field1 < y.field1
end
if o == "dsc" then
return x.field1 >= y.field1
end
error("Unknown option")
end
-- Example:
foo(FIRST, SECOND, "asc")
foo(FIRST, SECOND, "dsc")
Note that early returns make else unnecessary in this case but it might not always be true.
Anonymous function
But, hey, what's that? What if rather than a string option we pass something more bizarre like... something that can be called? Let's go with a simple function this time:
local asc = function (a, b) return a < b end
local dsc = function (a, b) return a >= b end
function bar (x, y, compare)
compare = compare or asc
return compare(x.field1, y.field1)
end
-- Example:
bar(FIRST, SECOND, asc)
bar(FIRST, SECOND, dsc)
bar(FIRST, SECOND, function (a, b) return a < b end)
Higher-order function
The previous example doesn't really look that good with a such simple operation, but let's take it as a base and let's create a function that will return us the desired function:
function make (compare)
return function (x, y) return compare(x.field1, y.field1) end
end
-- Example:
local asc = make(function (a, b) return a < b end)
local dsc = make(function (a, b) return a >= b end)
asc(FIRST, SECOND)
dsc(FIRST, SECOND)
Actual generation
Now then, let's try something closer to code generation. Lua gives us the ability to load chunks as we go with load* function family.
Please note that load in 5.1 is different from load in 5.2 or load in 5.3. In 5.1 you want to use loadstring instead of load.
function generate (op)
return load(string.format("return function (x, y) return x.field1 %s y.field1 end", op))()
end
-- Example:
local asc = generate("<")
local dsc = generate(">=")
asc(FIRST, SECOND)
dsc(FIRST, SECOND)

Related

Dispatching on arguments after the slurping operator (args...) in julia

How would you implement a function like this:
function foo(a,b...,c)
println(a,b,c)
end
foo(2,3,3,"last")
=> a = 2 , b = (3,3) , c = "last"
I cannot use something like:
function foo(a,b...)
c = b[end]
println(a,b,c)
end
Because I want to dispatch on c,
i.e.
I want to have methods:
foo(a,b...,c::Foo)
and
foo(a,b...,c::Bar)
Also I cant have something like this:
foo_wrapper(a,b...) = foo(a,b[1:end-1],b[end])
Because I also want to dispatch on foo in general.
Is this somehow posssible?
you can invert the order and then dispatch on an auxiliary function:
function foo(a,d...)
c = last(d)
b = d[begin:end-1]
return _foo(a,c,b...)
end
function _foo(a,c::Int,b...)
return c+1
end
function _foo(a,c::Float64,b...)
return 2*c
end
in the REPL:
julia> foo(1,2,3,4,5,6)
7
julia> foo(1,2,3,4,5,6.0)
12.0
julia> foo(1,2,8.0)
16.0
julia> foo(1,90) #b is of length zero in this case
91
The only option is to have c as a keyword parameter such as:
function foo(a,b...;c)
println(a," ",b," ",c)
end
And now you can do:
julia> foo(1,2,3;c="aa")
1 (2, 3) aa

Use varargin for multiple arguments with default values in MATLAB

Is there a way to supply arguments using varargin in MATLAB in the following manner?
Function
func myFunc(varargin)
if a not given as argument
a = 2;
if b not given as argument
b = 2;
if c not given as argument
c = a+b;
d = 2*c;
end
I want to call the above function once with b = 3 and another time while the previous one is running in the same command window with a = 3 and c = 3 and letting b take the default value in the function this time. How can it be done using varargin?
Here's the latest and greatest way to write the function (using arguments blocks from R2019b)
function out = someFcn(options)
arguments
options.A = 3;
options.B = 7;
options.C = [];
end
if isempty(options.C)
options.C = options.A + options.B;
end
out = options.A + options.B + options.C;
end
Note that this syntax does not allow you to say options.C = options.A + options.B directly in the arguments block.
In MATLAB < R2021a, you call this like so
someFcn('A', 3)
In MATLAB >= R2021a, you can use the new name=value syntax
someFcn(B = 7)
Here are two ways to do this which have been available since 2007a (i.e. a long time!). For a much newer approach, see Edric's answer.
Use nargin and ensure your inputs are always in order
Use name-value pairs and an input parser
nargin: slightly simpler but relies on consistent input order
function myFunc( a, b, c )
if nargin < 1 || isempty(a)
a = 2;
end
if nargin < 2 || isempty(b)
b = 2;
end
if nargin < 3 || isempty(c)
c = a + b;
end
end
Using the isempty check you can optionally provide just later arguments, for example myFunc( [], 4 ) would just set b=4 and use the defaults otherwise.
inputParser: more flexible but can't directly handle the c=a+b default
function myFunc( varargin )
p = inputParser;
p.addOptional( 'a', 2 );
p.addOptional( 'b', 2 );
p.addOptional( 'c', NaN ); % Can't default to a+b, default to NaN
p.parse( varargin{:} );
a = p.Results.a;
b = p.Results.b;
c = p.Results.c;
if isnan(c) % Handle the defaulted case
c = a + b;
end
end
This would get used like myFunc( 'b', 4 );. This approach is also agnostic to the input order because of the name-value pairs, so you can also do something like myFunc( 'c', 3, 'a', 1 );

Function with vector as argument in Octave

How can I make a function with a vector as input and a matrix as an output?
I have to write a function that will convert cubic meters to liters and English gallons. The input should be a vector containing volume values ​​in m ^ 3 to be converted. The result should be a matrix in which the first column contains the result in m ^ 3, the second liter, the third English gallon.
I tried this:
function [liter, gallon] = function1 (x=[a, b, c, d]);
liter= a-10+d-c;
gallon= b+15+c;
endfunction
You're almost there.
The x=[a,b,c,d] part is superfluous, your argument should be just x.
function [liter, gallon] = function1 (x);
a = x(1); b = x(2); c = x(3); d = x(4);
liter = a - 10 + d - c;
gallon = b + 15 + c;
endfunction
If you want your code to be safe and guard against improper inputs, you can perform such checks manually inside the function, e.g.
assert( nargin < 1 || nargin > 4, "Wrong number of inputs supplied");
The syntax x=[a,b,c,d] does not apply to octave; this is reserved for setting up default arguments, in which case a, b, c, and d should be given specific values that you'd want as the defaults. if you had said something like x = [1,2,3,4], then this would be fine, and it would mean that if you called the function without an argument, it would set x up to this default value.

Making closures type-stable dependent on the captured variable

For the function
function function_maker(N)
if N == 1
x = 1.0
else
x = 1
end
f(y) = x+y
end
I want the output of this to not be type-stable, but I want it to generate an f that is type-stable, i.e. uses the type of x determined by the value of N to generate a function dependent on N. Basically, I want the functions that come out of this to be performant, but the function_maker itself doesn't need to be performant because it's only used in the global scope or above a function barrier.
f = function_maker(1)
#code_warntype f(1)
Variables:
#self#::#f#9
y::Int64
Body:
begin
return ((Core.getfield)((Core.getfield)(#self#::#f#9, :x)::ANY, :contents)::ANY + y::Int64)::ANY
end::ANY
This doesn't happen by default. I tried f(y) = x::typeof(x)+y but that didn't work either. Is there a simple way to do this?
There's:
julia> function function_maker2(N)
if N == 1
let x = 1.0
return f(y) = x + y
end
else
let x = 1
return f(y) = x + y
end
end
end
function_maker2 (generic function with 1 method)
julia> f2 = function_maker2(1)
(::f) (generic function with 1 method)
julia> #code_warntype f2(1)
Variables:
#self#::#f#5{Float64}
y::Int64
Body:
begin
return (Base.add_float)((Core.getfield)(#self#::#f#5{Float64}, :x)::Float64, (Base.sitofp)(Float64, y::Int64)::Float64)::Float64
end::Float64
This version separates the x in each branch inside let blocks. Otherwise the compiler seems to get confused.

How to perform a conditional assignment on each element of the vector

I have a function like this:
y=-2 with x<=0
y=-2+3x^2 with 0=1
I need to compute this function on each element of the 1D matrix, without using a loop.
I thought it was possibile defining a function like this one:
function y= foo(x)
if x<=0
y=-2;
elseif x>=1
y=1;
else
y= -2+3*x.^2;
end
end
But this just produces a single result, how to operate on all elements? I know the . operator, but how to access the single element inside an if?
function b = helper(s)
if s<=0
b=-2;
elseif s>=1
b=1;
else
b= -2+3*s^2;
end
end
Then simply call
arrayfun(#helper, x)
to produce the behaviour you want of your function foo.
Another approach which doesn't need arrayfun() would be to multiply by the conditions:
y = -2*(x <= 0) + (-2+3*x.^2).*(x < 1).*(x > 0) + (x >= 1)
which you could also make a function. This will accept vector inputs for x e.g.
x = [1 4 0 -1 0.5];
y = -2*(x <= 0) + (-2+3*x.^2).*(x < 1).*(x > 0) + (x >= 1)
outputs
y =
1.0000 1.0000 -2.0000 -2.0000 -1.2500