【问题标题】:How does Dafny implement datatypes in C# and their hierarchy?Dafny 如何在 C# 中实现数据类型及其层次结构?
【发布时间】:2018-12-18 14:56:07
【问题描述】:

我实现了一个 .Net Web 应用程序,它使用在 Dafny 中完全验证的 .dll 库。它运作良好,与图书馆的沟通并不困难。这真是棒极了。

不幸的是,代码的某些部分看起来不太好,我想问一下是我没有很好地使用该库还是使用它的正确方法。我谈论数据类型。为了提问,我举了一个简单的例子。

module DafnyCalculation
{
    datatype Calculation = Sum(s1:int, s2:int) | Rest(r1:int, r2:int) 
                        | Mult(m1:int, m2:int) | Div (d1:int, d2:int)

    function method calculate(cal:Calculation): int
    {
        match cal
            case Sum(s1,s2) => s1+s2
            case Rest(r1,r2) => r1-r2
            case Mult(m1,m2) => m1*m2
            case Div(d1,d2) => 
                if(d2!=0) then d1/d2 
                else d1
    }
}

由于数据类型有多个构造函数,当生成 .dll 时,dafny 会自动创建一些类:Calculation、Base_Calculation、Calculation_Sum、Calculation_Rest、Calculation_Mult 和 Calculation_Div,并具有不同的参数。我在 C# 控制台应用程序中以下列方式使用 dll:

int result;
Base_Calculation cal;
Console.WriteLine("Enter first number: "); int x = int.Parse(Console.ReadLine());
Console.WriteLine("Enter second number: "); int y = int.Parse(Console.ReadLine());
Console.WriteLine("Choose operator:\n1)Sum\n2)Rest\n3)Mult\n4)Div\nOperator: "); 
int op = int.Parse(Console.ReadLine());
switch (op)
{
    case 1:
        cal = new Calculation_Sum((BigInteger)x, (BigInteger)y);
        break;
    case 2:
        cal = new Calculation_Rest((BigInteger)x, (BigInteger)y);
        break;
    case 3:
        cal = new Calculation_Mult((BigInteger)x, (BigInteger)y);
        break; 
    case 4 :
        cal = new Calculation_Div((BigInteger)x, (BigInteger)y);
        break;
    default:
        throw new Exception("Wrong option");
}
result = (int) _0_DafnyCalculation_Compile.__default.calculate(new Calculation(cal));
Console.WriteLine("Result: {0}", result);
Console.ReadLine();

我有一些基于示例的问题:

  1. 有没有什么方法可以调用函数calculate(cal:Calculation) 而不必构造一个新的Calculation 对象并直接包含一个“子类型”(Calculation_Sum、Calculation_Rest 等)?

  2. 可以 _0_DafnyCalculation_Compile.__default。可以避免吗?

  3. 是否需要导入 System.Numerics 并使用 BigInteger 转换 C# int 和 Dafny int?还是可以用其他方式完成?

提前谢谢你。我试图说明和清楚,如果任何部分无法理解,请随时与我联系。

【问题讨论】:

    标签: c# hierarchy implementation dafny


    【解决方案1】:

    感谢您的提问。

    1) 是的,现在有。今天,我检查了编译器的更改,它允许您编写

    Calculation.create_Sum(A, B)
    

    而不是以前的

    new Calculation(new Calculation_Sum(A, B))
    

    如果您的数据类型有类型参数,它们会紧跟在类型名称之后。

    2) 您可以通过 {:extern YourNameGoesHere} 提供您自己的名称来避免像 _0_DafnyCalculation_Compile 这样的重命名,它可以放在模块、类和方法等声明中。 (如果某些声明不支持您需要的:extern,请将其作为错误提交。)

    (我最近一直在进行一些编译器更改。在许多情况下,我可能能够自动删除 _0_ 前缀或 _Compile 后缀。我们会看到的。)

    3) 如果你使用 Dafny 的类型int,那么你必须使用你提到的BigInteger。但是如果你想使用原生整数类型,你可以在 Dafny 中声明你自己的整数类型。例如,

    newtype int32 = x | -0x8000_0000 <= x < 0x8000_0000
    

    声明一个 Dafny 类型 int32,其值在给定范围内。 (在此示例中,x 被推断为 int 类型,但您也可以显式指定类型,例如 newtype int32 = x: int | ...。)Dafny 编译器注意到此范围适合带符号的 32 位整数(写成int 在 C# 中),因此会将您的 Dafny 类型 int32 编译为 C# 的 int。这适用于所有原生 .NET 整数类型。

    如果出于某种原因您想要使用比您的范围允许的更大的本机整数类型,那么您可以使用 :nativeType 属性来指明您想要的内容。例如,

    newtype {:nativeType "short"} byteStoredUsing16Bits = x | -128 <= x < 128
    

    将使用 .NET short 来存储您的 byteStoredUsing16Bitstype。如果没有:nativeType 属性,Dafny 编译器将为byteStoredUsing16Bits 选择.NET 类型sbyte

    您还可以使用{:nativeType false}newtype 表示您不希望编译器使用本机整数(而是像往常一样使用BigInteger)。

    请注意,newtype 声明允许您定义自己的整数类型,但这些与 Dafny 的标准 int 不兼容。使用newtype 而不是声明子集类型(通过使用关键字type 而不是newtype)的主要原因是允许编译器使用不同的表示。如果需要在各种整数类型之间进行转换,请使用as 运算符。以下代码sn -p说明:

    var x: int := 70;
    var y: int32 := x as int32;
    var z: byteStoredUsing16Bits := y as byteStoredUsing16Bits;
    x := z as int;
    

    在数学上,as 运算符是一个部分恒等函数。也就是说,as 永远不会更改值,验证程序将检查您的转换是否来自目标类型中存在的值。 (作为练习,将示例中的 70 更改为 700 并观察验证者抱怨。)

    另外,请注意newtype 类型的所有中间表达式也必须遵守您指定的任何谓词。

    鲁斯坦

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多