How to handle bidirectional pin (inout) in a verilog task - task

I want to use a bidirectional data bus in my controller.Here's the code
module controller ( clk, data_out);
// Port Declaration
input clk;
inout [7:0] data_out;
reg [7:0] a;
reg [7:0] b;
wire [7:0] c;
// data should write to data_out (data_out act as output)
task write;
input c;
begin
assign data_out = a;
data_out <= c;
end
endtask
// data should read from data_out (data_out act as input)
task read;
output b;
begin
assign data_out = 8'bz;
b <= data_out;
end
endtask
endmodule
when I compile this i'm getting an error saying
LHS in procedural continuous assignment may not be a net: data_out.
it's says there is an error in assign data_out = a; and assign data_out = 8'bz;
I know assign should be done in always or initial block but in a task using those blocks are useless/give eroor
Then, how we can change directions of the bus in side a task??

You shouldn't use assign in initial and always blocks. I don't get why you necessarily want it in task?
Simply use assign alone. Assinging value to bidirectional port needs a flag that specifies what action- read or write- should be done. Syntax is like:
assign bidir_port = [flag] ? a : 1'bz;

Related

Why is `functionArgs` implemented twice? (i.e, as a primop and in `lib`)

Trying to understand callPackage, so looked up its implementation where it uses lib.functionArgs (source), but there is already a builtins.functionArgs primop, an alias of __functionArgs (implemented in C).
lib.functionArgs is defined as
/* Extract the expected function arguments from a function.
This works both with nix-native { a, b ? foo, ... }: style
functions and functions with args set with 'setFunctionArgs'. It
has the same return type and semantics as builtins.functionArgs.
setFunctionArgs : (a → b) → Map String Bool.
*/
functionArgs = f: f.__functionArgs or (builtins.functionArgs f);
and the __functionArgs attribute above is coming from setFunctionArgs (source):
/* Add metadata about expected function arguments to a function.
The metadata should match the format given by
builtins.functionArgs, i.e. a set from expected argument to a bool
representing whether that argument has a default or not.
setFunctionArgs : (a → b) → Map String Bool → (a → b)
This function is necessary because you can't dynamically create a
function of the { a, b ? foo, ... }: format, but some facilities
like callPackage expect to be able to query expected arguments.
*/
setFunctionArgs = f: args:
{
__functor = self: f;
__functionArgs = args;
};
I understand what setFunctionArgs does, and the comment above its declaration tells why it is necessary, but I can't understand it; both clauses of that sentence are clear but not sure how the first statement prevents the second one to be achieved (without setFunctionArgs, that is).
danbst also tried to elucidate this further,
lib.nix adds __functionArgs attr to mimic __functionArgs builtin. It
used to "pass" actual __functionArgs result down to consumers, because
builtin __functionArgs only works on top-most function args
but not sure what the "consumers" are, and couldn't unpack the last clause (i.e., "builtin __functionArgs only works on top-most function args"). Is this a reference to the fact that Nix functions are curried, and
nix-repl> g = a: { b, c }: "lofa"
nix-repl> builtins.functionArgs g
{ }
?
lib.functionArgs also doesn't solve this problem, but I'm probably off the tracks at this point.
Notes to self
__functor is documented in the Nix manual under Sets.
$ nix repl '<nixpkgs>'
Welcome to Nix version 2.3.6. Type :? for help.
Loading '<nixpkgs>'...
Added 11530 variables.
nix-repl> f = { a ? 7, b }: a + b
nix-repl> set_f = lib.setFunctionArgs f { b = 9; }
nix-repl> set_f
{ __functionArgs = { ... }; __functor = «lambda # /nix/store/16blhmppp9k6apz41gjlgr0arp88awyb-nixos-20.03.3258.86fa45b0ff1/nixos/lib/trivial.nix:318:19»; }
nix-repl> set_f.__functionArgs
{ b = 9; }
nix-repl> set_f set_f.__functionArgs
16
nix-repl> set_f { a = 27; b = 9; }
36
lib.functionArgs wraps builtins.functionArgs in order to provide reflective access to generic functions.
This supports reflection with builtins.functionArgs:
f = { a, b, c }: #...
Now consider the eta abstraction of the same function:
f' = attrs: f attrs
This does not support reflection with builtins.functionArgs. With setFunctionArgs, you can restore that information, as long as you also use lib.functionArgs.
I recommend to avoid reflection because everything that I've seen implemented with it can be implemented without it. It expands the definition of a function to include what should normally be considered implementation details.
Anyway, the primary motivation seems to be callPackage, which can be implemented with normal attrset operations if you change all packages to add ... as in { lib, stdenv, ... }:. I do have a morbid interest in this misfeature that is function reflection, so if anyone finds another use case, please comment.

How can I call a procedure declared inside another procedure?

I have a doubt regarding procedures in Db2. I created a stored procedure using "CREATE PROCEDURE", and inside that I have another which is declared using "DECLARE PROCEDURE". But, this procedure created by declare, cannot be called using "CALL".
When I try to run the procedure, Db2 returns:
[Code: -440, SQL State: 42884] DB2 SQL Error: SQLCODE=-440,
SQLSTATE=42884,
SQLERRMC=DMTLDBR.SP_DASH_CALENDARIO.PROCURA_DIA_UTIL_POST_DIA1;PROCEDURE,
DRIVER=4.25.1301
How should I call the declared procedure? (PROCURA_DIA_UTIL_POST_DIA1)
Code:
create or replace PROCEDURE "SP_DASH_CALENDARIO" (IN P_MES INTEGER)
BEGIN
------
DECLARE SQLSTATE CHAR(5) DEFAULT ' ';
DECLARE V_ANO_MES DECIMAL(6);
DECLARE V_ID_DIA ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_DIADIA.ID_DIA;
DECLARE V_VAL_REAL_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_VAL_TONVNEMA ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONVNEMA;
DECLARE V_VAL_FAT357_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_FAT357;
DECLARE V_VAL_PERDA_FAT_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_PERDA;
DECLARE V_SUM_VAL_REAL_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_REAL_CAL;
DECLARE V_SUM_VAL_TONVNE_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONVNE_CAL;
DECLARE V_SUM_VAL_TONLIQUIDO_ZBCL_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONLIQUIDO_ZBCL_CAL;
DECLARE V_SUM_VAL_TONLIQUIDO_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONLIQUIDO_CAL;
DECLARE V_SUM_VAL_FAT357_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_FAT357_CAL;
DECLARE V_VAL_TONLIQUIDO_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONLIQUIDO_CAL;
DECLARE V_VAL_TONVNE_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONVNE_CAL;
DECLARE V_VAL_TONLIQUIDO_ZBCL_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONLIQUIDO_ZBCL_CAL;
DECLARE V_VAL_PLANO_FAT_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_PLANEJ_MAN.VAL_PLANO;
DECLARE V_VAL_PLANO ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_PLANEJ_MAN.VAL_PLANO;
DECLARE V_TOTAL_PLANO_DESOVA_SEMANAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_PLANEJ_MAN.TOTAL_PLANO_DESOVA_SEMANAL;
DECLARE V_ID_DIASEMANA ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_DIADIA.ID_DIASEMANA;
DECLARE V_FLG_HOLIDAY ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_DIADIA.FLG_HOLIDAY;
DECLARE V_IND_LEGENDA DECIMAL(1);
DECLARE V_VARIANTE ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_PRODVARIANTE.ID_VARIANTE;
DECLARE V_VAL_PERDA ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_VAL_DESOVA ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_VAL_UHT ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_VAL_SUCO ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_VAL_REQ ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_TONLIQUIDO;
DECLARE V_FAT_UHT ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_FAT357;
DECLARE V_FAT_REQ ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_FAT357;
DECLARE V_ID_DIA_INI ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_DIADIA.ID_DIA;
DECLARE V_ID_DIA_FIM ANCHOR DATA TYPE TO DMTLDBR.TB_DIM_DIADIA.ID_DIA;
DECLARE FLAG_DIA_UTIL BOOLEAN;
DECLARE V_SUM_VAL_TONVNEMA_CAL ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_DASH_CALENDARIO.VAL_TONVNEMA_CAL;
DECLARE V_SUM_VAL_FAT357 ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_FAT357;
DECLARE V_SUM_VAL_ABATIMENTOREPORTADO ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_ABATIMENTOREPORTADO;
DECLARE V_SUM_VAL_ICMSZFMREPORTADO ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_ICMSZFMREPORTADO;
DECLARE V_PROC ANCHOR DATA TYPE TO DMTLDBR.TB_TMP_LOG_EXECUTION_PROC.SYNCPOINT_PROC;
SET V_PROC = 'SP_DASH_CALENDARIO';
-- =========================================================================================================
-- P R O C P R O C U R A _ D I A _ U T I L _ P O S T _ D I A 1
--
-- OBTEM O PRIMEIRO DIA ÚTIL DO MÊS (QUE NÃO SEJA DOMINGO NEM FERIADO)
--
-- =========================================================================================================
BEGIN
DECLARE PROCEDURE PROCURA_DIA_UTIL_POST_DIA1(IN P_ID_MES INTEGER)
BEGIN
DECLARE V_ACHOU DECIMAL(1) DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND BEGIN END;
SET V_ID_DIA = NULL;
L1: LOOP -- (LP01)
BEGIN -- (BE02.)
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' BEGIN END;
SELECT MIN(ID_DIA) INTO V_ID_DIA
FROM DMTLDBR.TB_DIM_DIADIA
WHERE ID_MES = P_ID_MES
AND ID_DIASEMANA <> 1 -- DOMINGO
AND FLG_HOLIDAY = 0;
END; -- (BE02.)
IF SQLSTATE = '00000' THEN
LEAVE L1;
--SET V_ACHOU = 1;
END IF;
END LOOP L1; -- (LP01.)
END;
END;
CALL DMTLDBR.PROCURA_DIA_UTIL_POST_DIA1(201909);
END
A Compound SQL (compiled) statement requires strict order of declarations / statements inside.
For example:
--#SET TERMINATOR #
CREATE OR REPLACE PROCEDURE TEST_LOCAL(P_I INT)
BEGIN
-- SQL-variable-declarations
DECLARE L_I INT;
-- DECLARE-CURSOR-statements
DECLARE C1 CURSOR FOR VALUES 1;
-- procedure-declaration
DECLARE PROCEDURE TEST_LOCAL_NESTED(P_J INT) BEGIN END;
-- handler-declarations
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END;
-- SQL-procedure-statements
CALL TEST_LOCAL_NESTED(P_I);
END#
Briefly for each BEGIN END block:
1-st: all SQL-variable-declarations
2-nd: all DECLARE-CURSOR-statements
3-rd: all procedure-declaration
4-th: all handler-declarations
All SQL-procedure-statements come afterwards only. These statements may contain nested BEGIN END blocks, where the same strict declaration / statement rules apply.
You have more than one mistake in the code shown in the question.
You are using a local procedure, that is the name for a procedure declared inside another procedure.
Local-Procedures work fine when used correctly.
Some suggestions to allow successful compilation:
the declare procedure must appear before any executable statements or new block in the calling procedure.
Move the statement SET V_PROC = 'SP_DASH_CALENDARIO' so that it appears
before the CALL to the local procedure (or anywhere within the main procedure block AFTER
all declarations (including after declaring the local procedure).
Additionally, remove the BEGIN (and matching END) on the line before DECLARE PROCEDURE.
You want all the declares to appear before any executable statement or new begin-end block.
the local procedure name must be unqualified both on the DECLARE and on the CALL
but you are using a qualifier on your CALL statement which will prevent Db2 from finding the local procedure.
The last part of your procedure will then look something like below:
...snip...
DECLARE V_SUM_VAL_ICMSZFMREPORTADO ANCHOR DATA TYPE TO DMTLDBR.TB_FATO_VENDASDIARIO.VAL_ICMSZFMREPORTADO;
DECLARE V_PROC ANCHOR DATA TYPE TO DMTLDBR.TB_TMP_LOG_EXECUTION_PROC.SYNCPOINT_PROC;
-- =========================================================================================================
-- P R O C P R O C U R A _ D I A _ U T I L _ P O S T _ D I A 1
--
-- OBTEM O PRIMEIRO DIA ÚTIL DO MÊS (QUE NÃO SEJA DOMINGO NEM FERIADO)
--
-- =========================================================================================================
DECLARE PROCEDURE PROCURA_DIA_UTIL_POST_DIA1(IN P_ID_MES INTEGER)
BEGIN
DECLARE V_ACHOU DECIMAL(1) DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND BEGIN END;
SET V_ID_DIA = NULL;
L1: LOOP -- (LP01)
BEGIN -- (BE02.)
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' BEGIN END;
SELECT MIN(ID_DIA) INTO V_ID_DIA
FROM DMTLDBR.TB_DIM_DIADIA
WHERE ID_MES = P_ID_MES
AND ID_DIASEMANA <> 1 -- DOMINGO
AND FLG_HOLIDAY = 0;
END; -- (BE02.)
IF SQLSTATE = '00000' THEN
LEAVE L1;
--SET V_ACHOU = 1;
END IF;
END LOOP L1; -- (LP01.)
END;
SET V_PROC = 'SP_DASH_CALENDARIO';
CALL PROCURA_DIA_UTIL_POST_DIA1(201909);
END#

Maintenance of reference counting in Z3

By some reasons I have to use C++ API and C API of Z3 together. In C++ API, reference counting of Z3 objects are well maintained and I needn't to worry about making mistakes. However I have to manually maintain reference counting for Z3 objects when I use C API because C++ API uses Z3_mk_context_rc to create the context. I have several problems on reference counting maintenance in Z3.
(1) If the reference counting of a Z3_ast is reduced to 0, what is responsible to release the memory of this Z3_ast? And when?
(2) The code below
void rctry(context & c)
{
expr x = c.int_const("x");
expr y = c.int_const("y");
Z3_ast res = Z3_mk_eq(c,x,y);
#ifdef FAULT_CLAUSE
expr z = c.int_const("z");
expr u = c.int_const("u");
Z3_ast fe = Z3_mk_eq(c,z,u);
#endif
std::cout << Z3_ast_to_string(c,res) << std::endl;
}
void main()
{
config cfg;
cfg.set("MODEL", true);
cfg.set("PROOF", true);
context c(cfg);
rctry(c);
}
Although I didn't increase reference count for AST referenced by res, the program works well. If FAULT_CLAUSE is defined, program still works, but it will output (= z u) instead of (= x y). How to explain this?
Thank you!
My golden rule for reference counting is: Whenever my program receives a pointer to a Z3 object, I immediately increment the ref count and I save the object somewhere safe (i.e., I now own 1 reference to that object). Only when I'm absolutely sure that I will not need the object any longer, then I will call Z3_dec_ref; from that point on, any access to that object will trigger undefined behavior (not necessarily a segfault), because I don't own any references anymore - Z3 owns all the rerferences and it can do whatever it wants to do with them.
Z3 objects are always deallocated when the ref count goes to zero; it's within the call to dec_ref() that the deallocation happens. If Z3_dec_ref() is never called (like in the example given), then the object may remain in memory so accessing that particular part of the memory might perhaps still give "ok looking" results, but that part of the memory may also be overwritten by other procedures so that they contain garbage.
In the example program given, we would need to add inc/dec_ref calls as follows:
void rctry(context & c)
{
expr x = c.int_const("x");
expr y = c.int_const("y");
Z3_ast res = Z3_mk_eq(c,x,y);
Z3_inc_ref(c, res); // I own 1 ref to res!
#ifdef FAULT_CLAUSE
expr z = c.int_const("z");
expr u = c.int_const("u");
Z3_ast fe = Z3_mk_eq(c,z,u);
Z3_inc_ref(c, fe); I own 1 ref to fe!
#endif
std::cout << Z3_ast_to_string(c, res) << std::endl;
#ifdef FAULT_CLAUSE
Z3_dec_ref(c, fe); // I give up my ref to fe.
#endif
Z3_dec_ref(c, res); // I give up my ref to res.
}
The explanation for the output (= z u) is that the second call to Z3_mk_eq
re-uses the chunk of memory that previously held res, because apparently
only the library itself had a reference to it, so it is free to chose what to
do with the memory. The consequence is that the call to Z3_ast_to_string
reads from the right part of the memory (that used to contain res), but the
contents of that part of the memory have changed in the meanwhile.
That was the long explanation for anybody who needs to manage ref counts in C. In
the case of C++ there is also a much more convenient way: the ast/expr/etc
objects contain a constructor that takes C objects. Therefore, we can construct
managed objects by simply wrapping them in constructor calls; in this
particular example that could be done as follows:
void rctry(context & c)
{
expr x = c.int_const("x");
expr y = c.int_const("y");
expr res = expr(c, Z3_mk_eq(c, x, y)); // res is now a managed expr
#ifdef FAULT_CLAUSE
expr z = c.int_const("z");
expr u = c.int_const("u");
expr fe = expr(c, Z3_mk_eq(c,z,u)); // fe is now a managed expr
#endif
std::cout << Z3_ast_to_string(c, res) << std::endl;
}
Within the destructor of expr there is a call to Z3_dec_ref, so that it
will be called automatically at the end of the function, when res and fe go
out of scope.

Use of context in C++ API

I have the following program , which transforms a string into a Boolean formula (string_to_formula), where I am defining expr_vector b(c). This code works, but I am not being able to reason about the context. What is the function of a context? Is there any way we can define the variable b just once? Why do we need to send the context to the function? And can this code be written in a more succinct way?
int main() { try {
context c;
expr form(c);
form = string_to_formula("x1x00xx011",c);
expr form1(c);
form1 = string_to_formula("1100x1x0",c);
solver s(c);
s.add(form && form1);
s.check();
model m = s.get_model();
cout << m << "\n";
}
expr string_to_formula(string str, context& c )
{
expr_vector b(c) ;
for ( unsigned i = 0; i < str.length(); i++)
{ stringstream b_name;
b_name << "b_" << i;
b.push_back(c.bool_const(b_name.str().c_str()));
}
expr formula(c);
formula = c.bool_val(true);
for( unsigned i = 0 ; i < str.length() ; ++i )
{ char element = str.at(i) ;
if ( element == '1' )
formula = formula && ( b[i] == c.bool_val(true) ) ;
else if ( element == '0' )
formula = formula && ( b[i] == c.bool_val(false) ) ;
else if ( element == 'x' )
continue;
}
return formula;
}
The context object is relevant for multi-threaded programs.
Each execution thread can have its own context, and they can be accessed without using any form of synchronization (e.g., mutexes).
Each expression belongs to a single context. We cannot use the same expression in two different contexts, but we can copy them from one context to another.
In Z3, expressions are maximally shared. For example, if we have an expressions such as (f T T) where T is a big term, then internally Z3 has only one copy of T. For implementing this feature, we use a hashtable. The hashtable is stored in the context.
If we use the same context C in two different execution threads, Z3 will probably crash due to race conditions updating C.
If your program has only one execution thread, you can avoid "moving" the context around by having a global variable.
The idea of context/manager is present in many libraries. For example, in CUDD (BDD library), they have a DdManager. In the script language Lua, they have a lua_State. These are all instances of the same idea.

Lambda Expressions in Delphi Prism/Oxygene

I have been experimenting with Lambda expressions in Oxygene. Very simple recursive lambda expression to calculate a fibonacci number :
var fib : Func<int32, int32>;
fib := n -> iif(n > 1, fib(n - 1) + fib(n - 2), n);
fib(3);
When I run this code I get a nullreferenceexception. Any ideas as to what I'm doing wrong?
You aren't doing anything wrong. If anything, the compiler should warn you about using fib, an unassigned variable, inside the body of the lambda.
However the compiler ought to be capturing fib as a location, so that when the assignment completes and the delegate is later invoked, fib is properly assigned and recursion should work as expected.
The most obvious possible reason for the failure is that Prism isn't capturing locations, but values, which would be grossly unintuitive and at odds with every other closure implementation in non-pure languages.
For example, try this code in JavaScript (contrary to Craig's assertion in the comments to this post, JavaScript also captures locations, not values):
<html>
<head>
<script language='javascript'>
function main()
{
var x = 1;
var f = function() { return x; };
alert(f());
x = 2;
alert(f());
}
</script>
</head>
<body>
<input type=button onclick="javascript:main()"></input>
</body>
</html>
The alert boxes after you click on the button show 1 and 2 respectively, while following Prism/Oxygene semantics they would show 1 both times.
Steve:
The issue has apparently been addressed in Delphi Prism 2010. The following code sample works in the official release.
var fib : Func<int32, int32>;
fib := n -> iif(n > 1, fib(n - 1) + fib(n - 2), n);
var i := fib(9); //1,1,2,3,5,8,13,21,34
MessageBox.Show(i.ToString);
The MessageBox shows the value 34.
In response to Jeroen's question, this code was run in the original, official release build, 3.0.21.661.
as a temporary workaround you can use:
var f := new class(f: Tfib := nil);
f.f := method(n : Int32): Int32
begin
if n > 1 then
Result := f.f(n-1) + f.f(n-2)
else
Result := n;
end;
f.f(3);
Prism handles the capture of local variables differently then native Delphi or C#.
In those 2 all references in your code of those locals will be mapped to fields of the compiler generated class that will hold your anonymous method.
In prism, these locals stay ordinary locals, yet the fields of this hidden fields are set when you instantiate the anonymous method.
One way to get a recursive lambda, would be to use a reference type to hold the lambda for you.
All of this sounds much more complicated then it really is.
2 methods of accomplishing your goal:
1)
var fib := new class(Call : Func<Integer, Integer> := nil);
fib.Call := n -> iif(n > 1, fib.Call(n - 1) + fib.Call(n - 2), n);
var x := fib.Call(3);
2)When you do not want to have a reference to this wrapper, you can do it like so:
var fib : Func;
with fibWrapper := new class(Call : Func<Integer, Integer> := nil) do
begin
fibWrapper.Call := n -> iif(n > 1, fibWrapper.Call(n - 1) + fibWrapper.Call(n - 2), n);
fib := fibWrapper.Call;
end;
btw, the reason behind Prism not following C# here, is that for threading and loop, this reusing of captured vars makes for hard weird runtime problems.
In Prism, captures are really captured the moment you assign the anonymous method or lambda. Which has a certain immuatble touch to it...
Cheers,
Robert
Does the same apply to Anonymous Methods? I'm guessing it does, but can't quite figure out the syntax to get this to run
var f : Tfib;
f := method(n : Int32): Int32
begin
if n > 1 then
Result := f(n-1) + f(n-2)
else
Result := n;
end;
Edit
It does.
var f := new class(call : TFib := nil);
f.call := method(n : Int32): Int32
begin
if n > 1 then
Result := f.call(n-1) + f.call(n-2)
else
Result := n;
end;

Resources