Vector

Vector は、長さが固定された配列です。標準ライブラリにおいて、次のように定義されています。

/-- `Vector α n` はサイズが `n` であるような `Array α` -/
structure Vector.{u} (α : Type u) (n : Nat) where
  /-- 地の配列 -/
  toArray : Array α
  /-- 配列のサイズ -/
  size_toArray : toArray.size = n
deriving Repr, DecidableEq

Vector の要素を定義するには、#v[a₁, a₂, .. aₙ] のように書きます。

#check #v[1, 2, 3]

用途

典型的な使用場面は、配列に対してその配列の長さが一定であることを保証したい場合です。

たとえば、配列の順番を逆にする関数を定義したいとします。「配列の要素を順に交換していくことで逆順にする」というアルゴリズムで実装してみます。

/-- 配列を逆順にする関数。
インデックスアクセスの妥当性証明を `swapIfInBounds` を使うことで回避している。 -/
def Array.myReverse₁ {α : Type} (arr : Array α) : Array α := Id.run do
  let mut array := arr
  let size := array.size
  for i in [0 : size / 2] do
    array := array.swapIfInBounds i (size - 1 - i)
  return array

#guard Array.myReverse₁ #[1, 2, 3, 4, 5] = #[5, 4, 3, 2, 1]
#guard Array.myReverse₁ (#[] : Array Nat) = #[]

ここで Array.swapIfInBounds ではなくて Array.swap を使用すると、インデックスアクセスの妥当性の証明が必要になります。しかし、let mut で宣言した配列の長さは変わってしまう可能性があるので、この証明は困難です。

def Array.myReverse₂ {α : Type} (arr : Array α) : Array α := Id.run do
  let mut array := arr

  -- `array` は可変な配列なので、
  -- `size = array.size` が常に成り立つとは限らない!
  let size := array.size

  for h : i in [0 : size / 2] do
    -- これは証明できる
    have : i < size := by
      dsimp [(· ∈ ·)] at h
      grind

    have : i < array.size := by
      -- `size = array.size` が成り立つことを Lean に伝える手段が難しくて
      -- 証明が回らない
      dsimp [(· ∈ ·)] at h
      fail_if_success grind
      sorry

    -- 同様に証明できない
    have : size - 1 - i < array.size := by
      dsimp [(· ∈ ·)] at h
      fail_if_success grind
      sorry

    array := array.swap i (size - 1 - i)
  return array

そこで Array の代わりに Vector を使用すると、配列の長さの情報が型レベルで固定されるので、Lean に「for によるループの間、配列のサイズが変わらない」ことを伝えることができ、インデックスアクセスの妥当性が容易に証明できるようになります。

def Array.myReverse₃ {α : Type} (arr : Array α) : Array α := Id.run do
  -- 配列ではなくて可変なベクトルとして保持する
  -- 可変変数だろうと型は変えられないので、長さが変わらないことを Lean に伝えられる
  let mut vec := arr.toVector
  let size := vec.size
  for h : i in [0 : size / 2] do
    -- 証明が通るようになった!
    have : i < vec.size := by
      dsimp [(· ∈ ·)] at h
      grind
    have : size - 1 - i < vec.size := by grind
    vec := vec.swap i (size - 1 - i)

  -- ベクトルを配列に戻して返す
  return vec.toArray