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;
Related
I was wondering if there is a way to add precondition checks in the Dafny generated code. For example, let's take the following code snippet:
method MultipleReturns(x: int, y: int) returns (more: int, less: int)
requires 0 < y
ensures less < x < more
{
more := x + y;
less := x - y;
}
I'd like that the resulting code in C++ to have the following check:
assert(0 < y);
If this is not available in Dafny, what options do I have? Thank you!
There is no automatic way to turn the requires clause into a run-time check. The condition of a requires clause is in a ghost context, so it may not be compilable in general. Also, if you verify your program, then you know the condition is always going to evaluate to true, so there's no point in also checking it at run time.
To support situations where the condition to be checked is too difficult to verify statically, and especially to support cross-language situations where the caller is not written in Dafny and therefore not verified, Dafny has expect statements. You can use expect in your example to trade the statically verified precondition for a run-time check:
method MultipleReturns(x: int, y: int) returns (more: int, less: int)
ensures less < x < more
{
RuntimeRequires(0 < y);
more := x + y;
less := x - y;
}
method RuntimeRequires(cond: bool)
ensures cond
{
expect cond, "precondition failure";
}
Note that without the requires clause, you will not get any static verification at call sites.
As one other variation, you could use both a requires clause and the RuntimeRequires method I showed. If you do, I would suggest you change the specification of RuntimeRequires from an ensures to a requires, to make sure you have copied the condition correctly.
method MultipleReturns(x: int, y: int) returns (more: int, less: int)
requires 0 < y
ensures less < x < more
{
RuntimeRequires(0 < y); // try changing this to 10 < y and see what happens
more := x + y;
less := x - y;
}
method RuntimeRequires(cond: bool)
requires cond
{
expect cond, "precondition failure";
}
Hi Relatively new to Dafny and have defined methods set2Seq and seq2Set for conversion between sets and seqs. But can only find how to write a function fseq2Set from sets to sequences.
I can not find how to define fseq2Set. As Lemmas can not reference methods this makes proving the identity beyond me. Any help much appreciated?
Code:
function method fseq2Set(se: seq<int>) :set<int>
{ set x:int | x in se :: x }
method seq2Set(se: seq<int>) returns (s:set<int>)
{ s := set x:int | x in se :: x; }
method set2Seq(s: set<int>) returns (se:seq<int>)
requires s != {}
ensures s == fseq2Set(se)
decreases |s|
{
var y :| y in s;
var tmp ;
if (s=={y}) {tmp := [];} else {tmp := set2Seq(s-{y});}
se := [y] + tmp;
assert (s-{y}) + {y} == fseq2Set([y] + tmp);
}
/* below fails */
function fset2Seq(s:set<int>):seq<int>
decreases s { var y :| y in s ; [y] + fset2Seq(s-{y}) }
lemma cycle(s:set<int>) ensures forall s:set<int> :: fseq2Set(fset2Seq(s)) == s { }
Ok, there is kind of a lot going on here. First of all, I'm not sure if you intended to do anything with the methods seq2Set and set2Seq, but they don't seem to be relevant to your failure, so I'm just going to ignore them and focus on the functions.
Speaking of functions, Danfy reports an error on your definition of fset2Seq, because s might be empty. In that case, we should return the empty sequence, so I adjusted your definition to:
function fset2Seq(s:set<int>):seq<int>
decreases s
{
if s == {} then []
else
var y := Pick(s);
[y] + fset2Seq(s - {y})
}
function Pick(s: set<int>): int
requires s != {}
{
var x :| x in s; x
}
which fixes that error. Notice that I also wrapped the let-such-that operator :| in a function called Pick. This is essential, but hard to explain. Just trust me for now.
Now on to the lemma. Your lemma is stated a bit weirdly, because it takes a parameter s, but then the ensures clause doesn't mention s. (Instead it mentions a completely different variable, also called s, that is bound by the forall quantifier!) So I adjusted it to get rid of the quantifier, as follows:
lemma cycle(s:set<int>)
ensures fseq2Set(fset2Seq(s)) == s
Next, I follow My Favorite Heuristicâ„¢ in program verification, which is that the structure of the proof follows the structure of the program. In this case, the "program" in question is fseq2Set(fset2Seq(s)). Starting from our input s, it first gets processed recursively by fset2Seq and then through the set comprehension in fseq2Set. So, I expect a proof by induction on s that follows the structure of fset2Seq. That structure is to branch on whether s is empty, so let's do that in the lemma too:
lemma cycle(s:set<int>)
ensures fseq2Set(fset2Seq(s)) == s
{
if s == {} {
} else {
}
...
Dafny reports an error on the else branch but not on the if branch. In other words, Dafny has proved the base case, but it needs help with the inductive case. The next thing that fset2Seq(s) does is call Pick(s). Let's do that too.
lemma cycle(s:set<int>)
ensures fseq2Set(fset2Seq(s)) == s
{
if s == {} {
} else {
var y := Pick(s);
...
Now we know from its definition that fset2Seq(s) is going to return [y] + fset2Seq(s - {y}), so we can copy-paste our ensures clause and manually substitute this expression.
lemma cycle(s:set<int>)
ensures fseq2Set(fset2Seq(s)) == s
{
if s == {} {
} else {
var y := Pick(s);
assert fseq2Set([y] + fset2Seq(s - {y})) == s;
...
Dafny reports an error on this assertion, which is not surprising, since it's just a lightly edited version of the ensures clause we're trying to prove. But importantly, Dafny no longer reports an error on the ensures clause itself. In other words, if we can prove this assertion, we are done.
Looking at this assert, we can see that fseq2Set is applied to two lists appended together. And we would expect that to be equivalent to separately converting the two lists to sets, and then taking their union. We could prove a lemma to that effect, or we could just ask Dafny if it already knows this fact, like this:
lemma cycle(s:set<int>)
ensures fseq2Set(fset2Seq(s)) == s
{
if s == {} {
} else {
var y := Pick(s);
assert fseq2Set([y] + fset2Seq(s - {y})) == fseq2Set([y]) + fseq2Set(fset2Seq(s - {y}));
assert fseq2Set([y] + fset2Seq(s - {y})) == s;
...
(Note that the newly added assertion is before the last one.)
Dafny now accepts our lemma. We can clean up a little by deleting the the base case and the final assertion that was just a copy-pasted version of our ensures clause. Here is the polished proof.
lemma cycle(s:set<int>)
ensures fseq2Set(fset2Seq(s)) == s
{
if s != {} {
var y := Pick(s);
assert fseq2Set([y] + fset2Seq(s - {y})) == fseq2Set([y]) + fseq2Set(fset2Seq(s - {y}));
}
}
I hope this explains how to prove the lemma and also gives you a little bit of an idea about how to make progress when you are stuck.
I did not explain Pick. Basically, as a rule of thumb, you should just always wrap :| in a function whenever you use it. To understand why, see the Dafny power user posts on iterating over collecion and functions over set elements. Also, see Rustan's paper Compiling Hilbert's epsilon operator.
I have a class that allocates an iterator on the heap and calls MoveNext() on that iterator. I want to prove that if MoveNext() returns true, Valid() holds for the iterator.
iterator Iter()
{}
class MyClass
{
var iter : Iter;
constructor ()
{
iter := new Iter();
}
method next() returns (more : bool)
requires iter.Valid();
modifies iter, iter._new, iter._modifies;
{
more := iter.MoveNext();
// This assertion fails:
assert more ==> iter.Valid();
}
}
I took a look at the output of /rprint, and the method MoveNext() contains ensures more ==> this.Valid(), which seems to imply my desired assertion. If I change iter to be locally allocated within the method next(), then Dafny verifies the assertion.
The problem is that nothing is known about what's in iter._new and iter._modifies. If this is in one of those sets, then this.iter may have changed during the call to MoveNext().
This body for next() confirms what I just said:
var i := iter;
more := iter.MoveNext();
assert i == iter; // this assertion fails
assert more ==> iter.Valid();
So, under the assumption more, Valid() does still hold of the iterator, but the iterator may no longer referenced by iter:
more := iter.MoveNext();
assert more ==> old(iter).Valid(); // this holds
Probably the way you want to solve this problem is to add a precondition to next():
method next() returns (more : bool)
requires iter.Valid()
requires this !in iter._new + iter._modifies // add this precondition
modifies iter, iter._new, iter._modifies
{
more := iter.MoveNext();
assert more ==> iter.Valid(); // this now verifies
}
Rustan
I was writing a little helper function toString(TypeSymbol t, M3 m) when I encountered a weird parser error.
The function has a lot of statements like:
...
}else if(object() := t){
return "object";
}else if(float() := t){
return "float";
}else if(double() := t){
return "double";
...
These work fine.
However, when I try this same pattern for int() or void(), the compiler gives an error, specifically on the = sign.
if(int() := t){}
^ Parse error here
As it often happens, I found the answer to this question while I was typing it up.
However, I think it'll be valuable for others so I will post it nonetheless.
I got the syntax for pattern matching in this answer: https://stackoverflow.com/a/21929342/451847
It seems that the 'proper' way of pattern matching is to prefix the type you want to test for with a \.
So, the code above becomes:
...
}else if(\object() := t){
return "object";
}else if(\float() := t){
return "float";
}else if(\double() := t){
return "double";
...
The non-\ syntax works for most of the cases but I think int() and void() have a different definition.
Despite of what Delphi reference says
structured types can contain other structured types; a type can have unlimited levels of structuring
with notable exception what structured typed constants
cannot contain file-type values at any level
I discovered what I cannot use record constant as an element of array constant of the same type.
Testcase
type
MyRecord = record MyField: Integer end;
const
Typical: array[0..1] of MyRecord = ((MyField: 0), (MyField: 1));
{ now I tried to achieve more clarity by declaring a specific constant }
Zero: MyRecord = (MyField: 0);
{ and compiler refused to accept that }
Bad: array[0..1] of MyRecord = (Zero, (MyField: 1)); { E2029 '(' expected but identifier 'Zero' found }
I tested this code with several Borland compilers, all of them exhibited the same behaviour. UPD: also the same for FPC, but not for GPC(!).
Question(s)
What is going on here? Am I correct with "Nested constants of nested structured types are unsupported" conclusion in the question title? Any more analysis of an issue?
It appears that this isn't possible, the underlying cause is that ZeroRec isn't truly a constant, it is more like an initialised static variable.
If {$WRITEABLECONST ON} is specified, then it can be trivially changed. Even with $WRITEABLECONST OFF, it can be changed by some creative type casting (tested in XE2):
program Project3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
MyRecord = record MyField: Integer end;
PMyRecord = ^MyRecord;
const
Typical: array[0..1] of MyRecord = ((MyField: 0), (MyField: 1));
{ now I tried to achieve more clarity by declaring a specific constant }
ZeroRec: MyRecord = (MyField: 0);
{ and compiler refused to accept that }
// Bad: array[0..1] of MyRecord = ((MyField: Zero), (MyField: 1)); { E2029 '(' expected but identifier 'Zero' found }
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
WriteLn(ZeroRec.MyField);
PMyRecord(#ZeroRec)^.MyField := 2;
WriteLn(ZeroRec.MyField);
readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
This will output
0
2
The behaviour is also evident with simple types,
Zero = 0;
ZeroRec: MyRecord = (MyField: Zero);
compiles as expected, however
Zero : Integer = 0;
ZeroRec: MyRecord = (MyField: Zero);
gives [DCC Error] Project3.dpr(19): E2026 Constant expression expected
What you are declaring is called a Typed Constant. And in this specific case it is an Array Constant. The documentation states (emphasis mine):
To declare an array constant, enclose the values of the array's elements, separated by commas, in parentheses at the end of the declaration. These values must be represented by constant expressions.
The code that the compiler objects to is where you attempt to use a typed constant where only a constant expression is allowed.
This is one of the most frustrating areas of the Delphi language because the language forces you to repeat yourself.