internal チュートリアル

このページは、immut や mutable に行列演算を追加し、その入力を検証する必要があるコントリビューター向けです。下流のコードは internal をインポートできず、ガードは公開メソッドを通じてしか見えません。規則は internal の設計 にあります。

クイックスタート

リポジトリの中では、moon.pkg でパッケージをインポートし、ガードをスコープに入れます。

///|
// moon.pkg
import {
  "Luna-Flow/linear-algebra/internal",
}
///|
using @internal {trait HasShape, ensure_square, ensure_square_checked}

日常的なタスク

検査付き・検査なしの組を追加する

検査付きのガードで検証してから検査なし形式を呼ぶことで、検査付き・検査なしの法則が構成上成り立ちます。

///|
pub fn[T : Add + Zero] Matrix::anti_trace(
  self : Matrix[T],
) -> Result[T, LinearAlgebraError] {
  match ensure_square_checked(self) {
    Ok(_) => Ok(self.unchecked_anti_trace())
    Err(err) => Err(err)
  }
}

///|
pub fn[T : Add + Zero] Matrix::unchecked_anti_trace(self : Matrix[T]) -> T {
  ensure_square(self)
  let n = self.row
  let mut sum = Zero::zero()
  for i in 0..<n {
    sum = sum + self[i][n - 1 - i]
  }
  sum
}

アクセス時にインデックスを検査する

行を選択するときは ensure_row_in_bounds を、ストレージのオフセットを計算する前には ensure_index_in_bounds を使ってください。平坦なオフセットだけを判定してはいけません。

外部から結果を観測する

テストで固定すべきなのは公開された振る舞いです。

///|
test "the same guard in both packages" {
  let i = @immut.Matrix::from_2d_array([[1, 2, 3]])
  let m = @mutable.Matrix::from_2d_array([[1, 2, 3]])
  let ei = match i.trace() {
    Err(e) => e.message
    Ok(_) => ""
  }
  let em = match m.trace() {
    Err(e) => e.message
    Ok(_) => ""
  }
  inspect(ei == em, content="true")
}

さらに進んで

リポジトリ内の新しい行列のような型は、HasShape を一度実装すればすべてのガードを使えます。リファクタリングの際はエラーの種類とメッセージを変えないでください。consistency のテストと下流のユーザーがそれに依存しています。

よくある落とし穴

  • 検査付きメソッドで中断するガードを呼ぶ。 検査付きメソッドが Err を返す代わりに中断してしまいます。
  • 変更した後に検査する。 mutable では、エラーで行列が変更されないよう、最初の書き込みの前に検証してください。

次のステップ