`overloading` 和 `adhoc_overloading` 有什么区别?

What's the difference between `overloading` and `adhoc_overloading`?

Isabelle 参考手册描述了执行基于类型的常量重载的方法:第 11.3 节中的 "Adhoc overloading of constants" 和第 5.9 节中的 "Overloaded constant definitions"。

似乎 5.9 重载要求在决定重载常量之前知道所有类型参数,而 11.3 (adhoc) 重载如果只有一个匹配则决定重载常量:

consts 
  c1 :: "'t ⇒ 'a set"
  c2 :: "'t ⇒ 'a set"

definition f1 :: ‹'a list ⇒ 'a set› where 
  ‹f1 s ≡ set s›

adhoc_overloading
  c1 f1

overloading
  f2 ≡ ‹c2 :: 'a list ⇒ 'a set›
begin
  definition ‹f2 w ≡ set w›
end

context 
  fixes s :: ‹int list›
begin
  term ‹c1 s› (* c1 s :: int set *)
  term ‹c2 s› (* c2 s :: 'a set  *)
end

两者有什么区别?我什么时候会用一个而不是另一个?

重载是伊莎贝尔逻辑的核心特征。它允许您使用可以在特定类型上定义的 "broad" 类型声明单个常量。用户很少需要手动执行此操作。它是用于实现类型 classes 的底层机制。例如,如果您定义类型 class 如下:

class empty =
  fixes empty :: 'a
  assumes (* ... *)

然后,class 命令将声明 'a' 类型的常量 empty,随后的实例化仅提供 定义 empty 用于特定类型,例如 natlist.

长话短说:在大多数情况下,重载是一种由更高级别的命令管理的实现细节。有时,需要进行一些手动调整,例如当您必须定义依赖于 class 约束的类型时。

临时重载 在我看来是一个误导性的名称。据我了解,它源于 Haskell(参见 this paper from Wadler and Blott)。在那里,他们用它来精确描述类型 class 机制,在 Isabelle 中将被创造为 "overloading"。在 Isabelle 中,临时重载 意味着完全不同的东西。这个想法是你可以用它来定义抽象语法(比如 monad 的 do-notation) Isabelle 的 ML 风格的简单类型系统 不能准确地捕捉到。与重载一样,您将定义一个 "broad" 类型的常量。但是这个常量从来没有得到任何定义!相反,您可以定义具有更具体类型的 new 常量。当 Isabelle 的术语解析器遇到抽象常量的使用时,它会尝试用具体常量替换

例如:您可以将 do-notation 与 optionlist 和其他一些类型一起使用。如果你这样写:

do { x <- foo; bar }

然后伊莎贝尔看到:

Monad_Syntax.bind foo (%x. bar)

在第二步中,根据 foo 的类型,它将把它翻译成 一个 这些可能的术语:

Option.bind foo (%x. bar)
List.bind foo (%x. bar)
(* ... more possibilities ...*)

同样,用户可能不需要明确处理这个概念。如果您从库中提取 Monad_Syntax,您将获得一个易于配置的临时重载应用程序。

长话短说:临时重载是一种在 Isabelle 中启用 "fancy" 语法的机制。新手可能会被它弄糊涂,因为如果内部翻译有问题,错误信息往往很难理解。