如何在 Idris 中反转 HVect?

How to reverse a HVect in Idris?

我是 Irdis 新手。是否可以反转 HVect?如果我在 HVect [String, Int] 上调用 reverse,它应该 return a HVect [Int, String],如果我在 HVect [String, Int, Day] 上调用 reverse,它应该 return a HVect [Day, Int, String]

我尝试重用 Data.Vect.reverse (Gist)

module reverse_hvect

import Data.HVect

reverse : HVect ts -> HVect (reverse ts)
reverse [] = []
reverse (x::xs) = (reverse xs) ++ [x]

但我明白了

Type checking .\reverse_hvect.idr
reverse_hvect.idr:7:9:When checking right hand side of reverse_hvect.reverse with expected type
        HVect (reverse (t :: ts))

Type mismatch between
        HVect (Data.Vect.reverse, go Type k ts [] ts ++ [t]) (Type of reverse xs ++ [x])
and
        HVect (Data.Vect.reverse, go Type (S k) (t :: ts) [t] ts) (Expected type)

Specifically:
        Type mismatch between
                Data.Vect.reverse, go Type k ts [] ts ++ [t]
        and
                Data.Vect.reverse, go Type (S k) (t :: ts) [t] ts
Holes: reverse_hvect.reverse

由于 Data.Vect.reverse 使用带累加器的内部函数 go,我编写了自己的 Vect.reverse,其结构与 HVect.reverse 相同(Gist )

module reverse_hvect

import Data.Vect
import Data.HVect

myReverse : Vect n a -> Vect n a
myReverse [] = []
myReverse {n = S k} (x::xs) = rewrite plusCommutative 1 k in (myReverse xs) ++ [x]

reverse : HVect ts -> HVect (myReverse ts)
reverse [] = []
reverse (x::xs) = (reverse xs) ++ [x]

但我收到另一个错误

Type checking .\reverse_hvect.idr
reverse_hvect.idr:12:9:When checking right hand side of reverse_hvect.reverse with expected type
        HVect (myReverse (t :: ts))

Type mismatch between
        HVect (myReverse ts ++ [t]) (Type of reverse xs ++ [x])
and
        HVect (replace (sym (replace (sym (replace (sym (plusZeroRightNeutral k)) Refl)) (replace (sym (plusSuccRightSucc k 0)) Refl))) (myReverse ts ++ [t])) (Expected type)

Specifically:
        Type mismatch between
                myReverse ts ++ [t]
        and
                replace (sym (replace (sym (replace (sym (plusZeroRightNeutral k)) Refl)) (replace (sym (plusSuccRightSucc k 0)) Refl))) (myReverse ts ++ [t])
Holes: reverse_hvect.reverse

在类型级别设置 rewrite 是个坏主意。我没有 Idris 类型检查器,但改编此 Agda 代码应该很简单:

open import Data.Nat.Base
open import Data.Vec hiding (reverse)

infixr 5 _∷ₕ_ _++ₕ_

nreverse : ℕ -> ℕ
nreverse  0      = 0
nreverse (suc n) = nreverse n + 1

vreverse : ∀ {n α} {A : Set α} -> Vec A n -> Vec A (nreverse n)
vreverse  []      = []
vreverse (x ∷ xs) = vreverse xs ++ (x ∷ [])

data HList : ∀ {n} -> Vec Set n -> Set where
  []ₕ  : HList []
  _∷ₕ_ : ∀ {n A} {As : Vec Set n} -> A -> HList As -> HList (A ∷ As)

_++ₕ_ : ∀ {n m} {As : Vec Set n} {Bs : Vec Set m} -> HList As -> HList Bs -> HList (As ++ Bs)
[]ₕ       ++ₕ ys = ys
(x ∷ₕ xs) ++ₕ ys = x ∷ₕ xs ++ₕ ys

reverseₕ : ∀ {n} {As : Vec Set n} -> HList As -> HList (vreverse As)
reverseₕ  []ₕ      = []ₕ
reverseₕ (x ∷ₕ xs) = reverseₕ xs ++ₕ (x ∷ₕ []ₕ)

即你只需要另一个reverse在反转塔中,即"reverses"一个数字。

顺便说一句,reverse for Vects in the Idris library is more involved than it should be. Here 是一个免重写版本。

user3237465 在 Idris 中的回答:

import Data.Vect
import Data.HVect

nreverse : Nat -> Nat
nreverse Z = Z
nreverse (S n) = nreverse n + 1

vreverse : Vect n a -> Vect (nreverse n) a
vreverse [] = []
vreverse (x :: xs) = vreverse xs ++ [x]

hreverse : HVect ts -> HVect (vreverse ts)
hreverse [] = []
hreverse (x :: xs) = hreverse xs ++ [x]

在不同的反面使用相同的结构,你的想法是正确的,但尝试了更难的结构。