如何在Isabelle中定义部分函数?

时间:2014-08-13 07:36:42

标签: isabelle

我尝试使用partial_function关键字定义部分函数。那没起效。这是最能表达直觉的那个:

partial_function (tailrec) oddity :: "nat => nat"
where
  "oddity Zero = Zero "
| "oddity (Succ (Succ n)) = n"

然后我尝试了以下内容:

partial_function (tailrec) oddity :: "nat => nat"
where
  "oddity arg = ( case arg of (Succ (Succ n)) => n
                          | Zero => Zero
                )"

partial_function (tailrec) oddity :: "nat => nat"
where
  "oddity (Succ(Succ n)) = n
   | oddity Zero = Zero"

partial_function (tailrec) oddity :: "nat => nat"
where
  "oddity n =
   (if n = Zero then Zero
    else if (n >= 2)
      then do { m ← oddity (n-2); m })"

他们都没有奏效。我想我的尝试有概念和句法问题,这些是什么?

2 个答案:

答案 0 :(得分:5)

您的定义存在两个问题:

  1. partial_function不支持左侧的模式匹配。必须使用右侧的case表达式进行模拟。

  2. 类型nat的构造函数是Suc0,而不是SuccZero。这就是为什么你的case表达式生成SuccZero不是数据类型构造函数的错误,以及为什么parital_function抱怨Zero是右边的额外变量。

  3. 总之,以下工作:

    partial_function (tailrec) oddity :: "nat => nat"
    where "oddity arg = (case arg of (Suc (Suc n)) => n | 0 => 0 )"
    

    您可以使用simp_of_case的{​​{1}}转换来恢复带模式匹配的简化规则:

    ~~/src/HOL/Library/Simps_Case_Conv

答案 1 :(得分:3)

关于你上一个例子的一些评论:

  1. Isabelle / HOL中没有if-then没有else。因此语法错误。要解决此问题,您必须为上一个else提供if - 分支,或者重写定义。 E.g。

    partial_function (tailrec) oddity :: "nat ⇒ nat"
    where
      "oddity n = (
        if n = 0 then 0
        else if n ≥ 2 then do { m ← oddity (n - 2); m }
        else undefined)"   
    
  2. 此时会出现“未解决的adhoc重载”错误。请记住,do-notation只是语法糖。让我们通过用

    查看do-block来试着看看实际发生了什么
    term "do { m ← oddity (n - 2); m }"
    

    由于仍有未解决的重载问题,我们可以将m的类型修改为'a list,并停用adhoc重载的“漂亮打印”,如下所示

    declare [[show_variants]]
    term "do { m ← oddity (n - 2); (m :: 'a list) }"
    

    结果是

    "List.bind (oddity (n - 2)) (λm. m)"
    

    因此,您可以看到,而不是您键入的分号;,会插入一个常量bind(确切的常量取决于类型)。没有bind注册类型nat,因此出现上述错误。虽然你可以定义某种“身份monad”,但这显示了在这里没有多少意义。相反,以下定义怎么样?

    partial_function (tailrec) oddity :: "nat ⇒ nat"
    where
      "oddity n = (
        if n = 0 then 0
        else if n ≥ 2 then oddity (n - 2)
        else undefined)"
    

    更新:为了完整起见,让我们看看我们如何定义上面提到的身份monad。首先,我们需要一个绑定操作,即一个常量取一个标识monad和一个返回一个标识monad的函数,并将这些参数组合成一个标识monad。第一个也是最简单的想法可能是

    definition "bind_id' x f = f x"
    

    这只是功能应用程序的逆序。但是,根据此定义,我们稍后会遇到bind_id'所需的(tailrec)单调性问题。因此我们改为使用

    definition "bind_id x f = (if x = undefined then undefined else f x)"
    

    保证bind_id x f只要undefinedx,因此是单调的。然后我们为monadic bind的adhoc重载注册这个新的常量,如此

    adhoc_overloading
      Monad_Syntax.bind bind_id
    

    现在仍然需要证明bind_id w.r.t的单调性。 mono_tailrec,留作练习(只是模仿mono_optionPartial_Function已经完成的操作。然后,您接受使用do-notation的定义。

  3. 您可能不会oddity 1未定义。但由于我不确定oddity的目的,我无法确定。