通过重复划分进行有根据的递归

时间:2016-11-15 14:00:33

标签: recursion idris induction totality

假设我有一些自然数d≥2 n&gt; 0 ;在这种情况下,我可以从 n 中拆分 d ,并获得 n = m * d k < / i>,其中 m 不能被 d 整除。

I'd like to use this repeated removal of the d-divisible parts as a recursion scheme;所以我认为我为导致 m Steps制作数据类型:

import Data.Nat.DivMod

data Steps: (d : Nat) -> {auto dValid: d `GTE` 2} -> (n : Nat) -> Type where
  Base: (rem: Nat) -> (rem `GT` 0) -> (rem `LT` d) -> (quot : Nat) -> Steps d {dValid} (rem + quot * d)
  Step: Steps d {dValid} n -> Steps d {dValid} (n * d)

并编写一个递归函数,计算给定Stepsd对的n

total lemma: x * y `GT` 0 -> x `GT` 0
lemma {x = Z} LTEZero impossible
lemma {x = Z} (LTESucc _) impossible
lemma {x = (S k)} prf = LTESucc LTEZero

steps : (d : Nat) -> {auto dValid: d `GTE` 2} -> (n : Nat) -> {auto nValid: n `GT` 0} -> Steps d {dValid} n
steps Z {dValid = LTEZero} _ impossible
steps Z {dValid = (LTESucc _)} _ impossible
steps (S d) {dValid} n {nValid} with (divMod n d)
  steps (S d) (q * S d) {nValid} | MkDivMod q Z _ = Step (steps (S d) {dValid} q {nValid = lemma nValid})
  steps (S d) (S rem + q * S d) | MkDivMod q (S rem) remSmall = Base (S rem) (LTESucc LTEZero) remSmall q

但是,steps不被视为总数,因为递归调用没有明显的理由(q和{{之间没有结构关系) 1}})。

但我也有一个功能

n
带着无聊的证据。

我可以在total wf : (S x) `LT` (S x) * S (S y) 的定义中使用wf向Idris解释steps是否合计?

1 个答案:

答案 0 :(得分:1)

这是使用有根据的递归来做你所要求的一种方法。我敢肯定,有更好的方法。在下文中,我将使用标准LT函数,它允许我们实现我们的目标,但是我们需要解决一些障碍。

不幸的是,LT是一个函数,而不是类型构造函数或数据构造函数,这意味着我们无法定义一个实现 WellFounded LT的类型类。以下代码是针对这种情况的解决方法:

total
accIndLt : {P : Nat -> Type} ->
         (step : (x : Nat) -> ((y : Nat) -> LT y x -> P y) -> P x) ->
         (z : Nat) -> Accessible LT z -> P z
accIndLt {P} step z (Access f) =
  step z $ \y, lt => accIndLt {P} step y (f y lt)

total
wfIndLt : {P : Nat -> Type} ->
        (step : (x : Nat) -> ((y : Nat) -> LT y x -> P y) -> P x) ->
        (x : Nat) -> P x
wfIndLt step x = accIndLt step x (ltAccessible x)

我们需要一些处理小于关系的帮助引理,可以在this gist(Order模块)中找到引理。它是我最近开始的个人图书馆的一个子集。我确信帮助者引理的证据可以最小化,但这不是我的目标。

导入Order模块后,我们可以解决问题(我稍微修改了原始代码,更改它或编写包装器以获得原始类型并不困难):

total
steps : (n : Nat) -> {auto nValid : 0 `LT` n} -> (d : Nat) -> Steps (S (S d)) n
steps n {nValid} d = wfIndLt {P = P} step n d nValid
  where
    P : (n : Nat) -> Type
    P n = (d : Nat) -> (nV : 0 `LT` n) -> Steps (S (S d)) n

    step : (n : Nat) -> (rec : (q : Nat) -> q `LT` n -> P q) -> P n
    step n rec d nV with (divMod n (S d))
      step (S r + q * S (S d)) rec d nV | (MkDivMod q (S r) prf) =
        Base (S r) (LTESucc LTEZero) prf q
      step (Z + q * S (S d))       rec d nV | (MkDivMod q Z     _) =
        let qGt0 = multLtNonZeroArgumentsLeft nV in
        let lt = multLtSelfRight (S (S d)) qGt0 (LTESucc (LTESucc LTEZero)) in
        Step (rec q lt d qGt0)

我在divMod模块的contrib/Data/Nat/DivMod/IteratedSubtraction.idr函数之后对steps进行了建模。

完整代码可用here

警告:整体检查程序(从Idris 0.99发布版本开始)接受steps为总计。它最近已修复并适用于我们的问题(我使用Idris 0.99-git:17f0899c进行了测试)。