伊德里斯的观点 - 伊德里斯书中的类型驱动开发清单10.5

时间:2017-05-01 14:57:43

标签: types idris

目前,我正在通过Edwin Brady的“使用Idris进行类型驱动开发”文本。不用说,文本列出了SplitList和splitList(封面函数)的代码。但是,我想知道文本中给出的封面函数是否可以简化为我在下面生成的封面函数 - 这不能按预期工作。有人可以让我知道为什么我的splitList不起作用?我收到的错误消息在下面进一步生成。非常感谢。

data SplitList : List ty -> Type where
  Null      : SplitList [ ]
  Singleton : SplitList [x]
  Pair      : (lhs: List ty) -> (rhs: List ty) -> SplitList (lhs ++ rhs)

splitList : (xs: List ty) -> SplitList xs
splitList [ ] = Null
splitList [x] = Singleton
splitList xs  = 
  let 
    mid = div (List.length xs) 2 
    lhs = List.take mid xs
    rhs = List.drop mid xs
  in
    Pair lhs rhs

错误消息:

键入检查./foo.idr foo.idr:53:11: 检查具有预期类型的​​splitList的右侧时         SplitList xs

两者之间的类型不匹配         SplitList(lhs ++ rhs)(对lhs rhs的类型) 和         SplitList xs(预期类型)

具体做法是:         类型不匹配                 lhs ++ rhs         和                 XS 孔:Main.splitList

1 个答案:

答案 0 :(得分:4)

此错误消息的原因是Idris没有看到xs = lhs ++ rhs,您必须说服Idris。

首先,让我们将上述事实证明是一个单独的引理:

total
takeDropAppend : (n : Nat) -> (xs : List ty) -> xs = List.take n xs ++ List.drop n xs
takeDropAppend Z _ = Refl
takeDropAppend (S n) [] = Refl
takeDropAppend (S n) (x :: xs) = cong $ takeDropAppend n xs

现在我们可以按如下方式使用它:

total
splitList : (xs: List ty) -> SplitList xs
splitList [ ] = Null
splitList [x] = Singleton
splitList xs =
  let
    mid = divNatNZ (List.length xs) 2 SIsNotZ
  in
    rewrite takeDropAppend mid xs in
    Pair (List.take mid xs) (List.drop mid xs)

我将div更改为divNatNZ以使该功能成为总计并采用快捷方式,将lhsrhs替换为其定义。我应该使用(更高效)List.splitAt标准函数,但它会使证明变得复杂。