protected
protected は、ある名前空間 Hoge にある定義 foo に対して、短い名前 foo でアクセスすることを禁止するものです。
namespace Playground
/-- protected が付いていない定義 -/
def ordianal_hoge := "hoge"
/-- protected が付いている定義 -/
protected def protected_hoge := "hoge"
end Playground
namespace Playground
-- 名前空間の中なので、短い名前でアクセスできる
-- (通常の挙動)
#check ordianal_hoge
-- 名前空間を開いているが、短い名前ではアクセスできない
#check_failure protected_hoge
-- 名前空間名を補えばアクセスできる
#check Playground.protected_hoge
end Playground
section
open Playground
-- 名前空間を `open` しているので、
-- 短い名前でアクセスできる(通常の挙動)
#check ordianal_hoge
-- 名前空間を `open` しているが、短い名前ではアクセスできない
#check_failure protected_hoge
end
構文
def コマンドに対してだけでなく、indudctive コマンドで生成されるコンストラクタに対しても使用可能です。
/-- 2分木 -/
inductive BinTree (α : Type) where
| empty : BinTree α
| protected node : α → BinTree α → BinTree α → BinTree α
section
-- 名前空間を開く
open BinTree
-- 名前空間を open しているが、
-- コンストラクタに短い名前でアクセスできない
#check_failure node
#check BinTree.node
-- protected でない方は短い名前でアクセスできる
#check empty
end
また structure コマンドで生成されるアクセサ関数やコンストラクタに対しても使用可能です。
structure Sample where
-- コンストラクタも protected にできる
protected mk ::
bar : Nat
protected hoge : String
section
open Sample
-- 名前空間を open しているので bar には短い名前でアクセスできる
#check bar
-- hoge には短い名前でアクセスできない
#check_failure hoge
end
用途
機能から想像がつくと思いますが、protected は混同を避けるために使用されます。
protected を使うべき典型的な状況は、型クラスのメソッドが export されている場合です。
/-- 文字列をパースして `α` 型の項を得る方法を提供する型クラス -/
class OfString (α : Type) where
ofString : String → Option α
export OfString (ofString)
型クラスのメソッドを用意するときに、関数名は往々にしてそのメソッドと同じ名前にするので、紛らわしさが生じます。
namespace Bool
-- `Bool` 名前空間の中にいると、
-- `Bool.ofString` と `OfString.ofString` が紛らわしい
def ofString (s : String) : Option Bool :=
match s with
| "true" => some true
| "false" => some false
| _ => none
instance : OfString Bool where
ofString := ofString
-- `Bool.ofString` の方を指している
/- info: Bool.ofString (s : String) : Option Bool -/
#check ofString
end Bool
-- `OfString.ofString` の方を指している
/- info: OfString.ofString {α : Type} [self : OfString α] : String → Option α -/
#check ofString
protected を使用すると、「型クラスのメソッドの具体的な実装の方を指したいときは、明示的に名前空間を補う」というルールにできるので、紛らわしさが改善されます。
namespace Unit
protected def ofString (s : String) : Option Unit :=
match s with
| "()" => some ()
| _ => none
instance : OfString Unit where
ofString := Unit.ofString
-- `OfString.ofString` の方を指している
/- info: OfString.ofString {α : Type} [self : OfString α] : String → Option α -/
#check ofString
end Unit
名前空間がネストしているとき
名前空間がネストしていないとき、protected は「フルネームを強制する」と説明しても問題ありません。しかし、名前空間がネストしているときにはその説明は誤りになります。
以下に示すように、Outer.Inner.sample という名前を protected で修飾すると、最も近い名前空間の修飾名である Inner を省略することができなくなります。
namespace Outer
namespace Inner
protected def sample := "sample"
-- フルネームを強制するのであれば失敗するべきだが、成功する。
#check Inner.sample
-- Inner 名前空間を省略することはできない
#check_failure sample
end Inner
end Outer