Dafny Dafny
首页
  • 入门介绍

    • 什么是dafny?
  • 用起来吧!

    • 安装
    • 快速上手
    • 可能遇到的问题?
  • Dafny快速入门

    • 基础学习 Basic
    • 方法 Method
    • 关键字 Keyword
    • 函数 Function
    • 类 Class
    • 泛型 Generics
    • 声明 Statement
    • 表达式 Expression
  • Dafny简单例子

    • 寻找最大最小数和
    • 斐波那契数列
    • 线性查询
    • 引理-计算序列非负元素个数
    • 集合
    • 终止
  • Dafny指导

    • 介绍
    • 方法 Methods
    • 前置/后置条件 Pre/Postconditions
    • 断言 Assertions
    • 函数 Functions
    • 循环不变体 Loop Invariants
    • 数组 Arrays
    • 量词(函数) Quantifiers
    • 谓词(函数) Predicates
    • 框架 Framing
    • 二分搜索 Binary Search
    • 总结
  • Dafny进阶语法

    • 引理和归纳 Lemmas and Induction
    • 模块 Modules
    • 集合 sets
    • 序列 sequence
    • 终止 Terminal
    • 值类型 Values Types
  • 实践探索

    • 自动归纳
    • 自动调用引理
    • 定义、证明、算法正确性
    • 各种推导式
    • 不同类型的证明
    • 集合元素上的函数
    • 在集合上的迭代
  • 常用工具

    • Type System
    • Style Guide
    • Cheet Sheet
✨收藏
  • 简体中文
  • English
💬社区留言板
GitHub (opens new window)

Dafny

新一代验证语言
首页
  • 入门介绍

    • 什么是dafny?
  • 用起来吧!

    • 安装
    • 快速上手
    • 可能遇到的问题?
  • Dafny快速入门

    • 基础学习 Basic
    • 方法 Method
    • 关键字 Keyword
    • 函数 Function
    • 类 Class
    • 泛型 Generics
    • 声明 Statement
    • 表达式 Expression
  • Dafny简单例子

    • 寻找最大最小数和
    • 斐波那契数列
    • 线性查询
    • 引理-计算序列非负元素个数
    • 集合
    • 终止
  • Dafny指导

    • 介绍
    • 方法 Methods
    • 前置/后置条件 Pre/Postconditions
    • 断言 Assertions
    • 函数 Functions
    • 循环不变体 Loop Invariants
    • 数组 Arrays
    • 量词(函数) Quantifiers
    • 谓词(函数) Predicates
    • 框架 Framing
    • 二分搜索 Binary Search
    • 总结
  • Dafny进阶语法

    • 引理和归纳 Lemmas and Induction
    • 模块 Modules
    • 集合 sets
    • 序列 sequence
    • 终止 Terminal
    • 值类型 Values Types
  • 实践探索

    • 自动归纳
    • 自动调用引理
    • 定义、证明、算法正确性
    • 各种推导式
    • 不同类型的证明
    • 集合元素上的函数
    • 在集合上的迭代
  • 常用工具

    • Type System
    • Style Guide
    • Cheet Sheet
✨收藏
  • 简体中文
  • English
💬社区留言板
GitHub (opens new window)
  • 实践探索

  • 常用工具

    • Dafny type system
    • Style Guide for Dafny programs
      • 命名约定
      • 前缀方法
        • 代码布局
        • Braces
        • Imports
      • 缩进和换行
        • 制表符还是空格?
        • 最大字符限制
        • 换行符
        • 函数、方法、谓词和引理
      • 需要避免的事情
        • 括号
        • 空格
        • 类型声明
        • 函数、方法、谓词和引理声明
      • 建议
        • Externs
        • 需要考虑的事项
    • Cheet Sheet
  • 资源
  • 常用工具
lijiahai
2022-03-26
目录

Style Guide for Dafny programs

# Style Guide for Dafny Programmers

Dafny 文档 (opens new window)

  • 命名约定
    • 方法前缀 (opens new window)
  • 代码布局
    • Braces (opens new window)
    • Imports (opens new window)
  • 缩进和换行
    • 制表符还是空格? (opens new window)
    • 最大字符限制 (opens new window)
    • 换行符 (opens new window)
    • 函数、方法、谓词和引理 (opens new window)
  • 需要避免的事情
    • 括号 (opens new window)
    • 空格
      • 类型声明 (opens new window)
      • 函数、方法、谓词和引理声明 (opens new window)
  • 建议
    • Externs (opens new window)
    • 需要考虑的事项 (opens new window)

本样式指南提供了 Dafny 代码的编码约定。

此文档仍在进行中。 请随时添加更多建议。

# 命名约定

任何变量都以camelCase命名。

var minValue := 1;
var cipherMessage := "Hello World";
1
2

任何引理、谓词、函数、方法、类、模块、数据类型和新类型都以PascalCase命名。

method FindIndex(arr: seq<int>, k: int)
    ...
1
2

任何静态或全局 常量 都以 UPPERCASE_WITH_UNDERSCORES 命名。

static const MONTHS_IN_A_YEAR := 12
1

# 前缀方法

当变量或方法位于类/模块中时,避免使用冗余名称。

class Integer {

    // The following method converts the given integer
    // to a string.
    //
    // this method name can be simplified to ToString()
    // so that the method call is Integer.ToString(i)
    // instead of Integer.IntegerToString(i).

    // YES
    method ToString(i: int) returns (s: string)
        ...

    // NO
    method IntegerToString(i: int) returns (s: string)
        ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 代码布局

# Braces

默认情况下,左大括号在同一行。

module M {
    ...
    method Met() {
        ...
    }
}
1
2
3
4
5
6

如果方法(或函数、引理等)签名太长而不能放在一行中,或者如果签名至少有一个规范子句,则左大括号将换行。

module M {
    ...
    method Met(i: int) returns (j: int)
        requires i % 2 == 0
        ensures j > 10
    {
        ...
    }
}
1
2
3
4
5
6
7
8
9

这适用于每个范围:module、class、predicate、if、while 等等。

# Imports

默认情况下,导入模块而不打开它们。

import Coffee
...
1
2

但是,如果某个模块的某些成员非常频繁地使用,请使用 opened 导入它:

import opened Donut
...
1
2

当一个文件使用两个模块并且它们都定义同名的方法时,不要将它们导入 opened。

import MyModule
import YourModule
...
method MyMethod() {
    MyModule.foo();
    YourModule.foo();
}
1
2
3
4
5
6
7

在这种情况下,如果要缩短模块名称,请使用简写名称导入。

import M = MyModuleWithACumbersomeName
import Y = YourModuleWithACumbersomeName
...
method MyMethod() {
    M.foo();
    Y.foo();
}
1
2
3
4
5
6
7

常见的导入,例如 StandardLibrary 和 Native,应该组合在一起,然后是自定义模块导入,中间有一个空行。

import opened StandardLibrary
import opened Native

import opened Donut
import Coffee
1
2
3
4
5

虽然不是必需的,但建议保持 imports 和 includes 的字母顺序,除非将它们按逻辑分组更有意义。

# 缩进和换行

# 制表符还是空格?

空格优于制表符。 选项卡只能用于与包含选项卡的现有代码保持一致。

每个缩进使用 2 个空格。

# 最大字符限制

虽然没有特别的严格要求,但一般建议每行最多 120 个字符。

# 换行符

在连续的函数、方法、谓词和引理之间使用换行符,提高代码可读性。

以换行符结束每个文件。

# 函数、方法、谓词和引理

每个 Dafny 方法都有以下签名。

method {:<attributes>} MethodName(param1: Type, param2: Type) returns (ret: Type)
    requires P()
    modifies param2
    ensures Q()
    decreases param1
1
2
3
4
5

如果可能,将 MethodName 和 returns 语句放在同一行,因为关键字 returns 与其他方法规范子句不同,例如 requires、modifies、ensures 和 decreases ,应该按这个顺序出现。 每个方法规范子句应该在单独的行上,缩进。

如果 Method 签名太长,我们可以将其分解。

method {:<attributes>} MethodName(param1: Type, param2: Type,
        param3: Type, param4: Type, param5: Type)
    returns (ret1: Type, ret2: Type, ret3: Type, ret4: Type,
        ret5: Type)
    requires P1()
    requires P2()
    requires P3()
    modifies param2
    modifies param3
    ensures Q1()
    ensures Q2()
    decreases param1
1
2
3
4
5
6
7
8
9
10
11
12

多个 requires 或 ensures 可以合并为一个:

requires
    && P1()
    && P2()
    && P3()
1
2
3
4

相同的规则适用于 function、predicate 和 lemma 定义。

# 需要避免的事情

# 括号

在许多情况下,Dafny 不需要在表达式周围加上括号。 这里有些例子。

  • If-Else-While 语句
// YES
var i := 1;
while i < 10 {
    ...
    if 1 < i {
        ...
    }
    ...
}

// NO
var i := 1;
while (i < 10) {
    ...
    if (1 < i) {
        ...
    }
    ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • 带有表达式参数的语句
// YES
assert x < 100;
print x;

// NO
assert(x < 100);
print(x);
1
2
3
4
5
6
7
  • 简单的布尔/算术表达式
// YES
method Collatz(num: nat)
    decreases *
{
    var n := num;
    while 1 < n
        decreases *
    {
        n := if n % 2 == 0 then n / 2 else n * 3 + 1;
    }
}

// NO
method Collatz(num: nat)
    decreases *
{
    var n := num;
    while (1 < n) // unnecessary parentheses
        decreases *
    {
        n := if ((n % 2) == 0) then (n / 2) else ((n * 3) + 1); // unnecessary parentheses
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 空格

避免表达式中不必要的空格。

# 类型声明

类型声明应该具有variableName: variableType的形式。

// YES
const one: int := 1
class {:extern} Util {
    var {:extern} Exception: System.String
}

// NO
const one : int := 1 // unnecessary whitespace
class {:extern} Util {
    var {:extern} Exception : System.String // unnecessary whitespace
}
1
2
3
4
5
6
7
8
9
10
11

如果 Dafny 可以推断出该类型,请将其省略,除非您认为它在程序中提供了有用的文档。 所以,上面的常量 one 最好声明为

const one := 1
1

# 函数、方法、谓词和引理声明

function、method、predicate 和 lemma 定义应该具有 FunctionName(parameterName: parameterType, ...) 的形式。

// YES
function method Foo<int>(i: int): int

// NO
function method Foo<int> (i : int) : int // unnecessary whitespace
1
2
3
4
5

Avoid too little or too much whitespace that reduces the overall readability.

// YES
lemma MyLemma<A, B>(x: seq<seq<A>>, y: B) {
    ...
}

// NO
lemma MyLemma <A,B> ( x : seq<seq<A>> , y :B){
    ...
}
1
2
3
4
5
6
7
8
9

# 建议

本节描述了一些建议,这些建议可以帮助使代码更具可读性和易于遵循,尽管没有严格执行。

# Externs

尽可能在 Dafny 和目标语言(例如 C#、Java 等)中将它们命名为相同的名称,这样在 Dafny 中我们只需编写 {:extern},而不是 {:extern "<name>"}。

# 需要考虑的事项

在 Dafny 中设计/实施程序之前思考这些问题。

  • 这个变量名/函数名X是个好名字吗?
  • 这个方法M在模块X中有意义吗? 它不应该在模块 Y 中吗?
  • 定义X是否属于文件Y.dfy?
  • X.dfy 是一个好的文件名吗?
编辑 (opens new window)
#1#1#1# #-
上次更新: 2022/04/06, 20:36:17
Dafny type system
Cheet Sheet

← Dafny type system Cheet Sheet→

最近更新
01
寻找最大和最小数
04-06
02
斐波那契数列
04-06
03
线性查询
04-06
更多文章>
Theme by Vdoing | Copyright © 2022-2022 Li Jiahai | Dafny Community | 2022
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式