|
1 | 1 | /- |
2 | 2 | # ToString |
3 | | -`ToString` は、文字列への変換を行う型クラスです。 |
| 3 | +`ToString` は、文字列 `String` への変換方法を提供する型クラスです。`ToString` のインスタンスになっている型の項は、`toString` 関数で文字列に変換することができます。 |
4 | 4 | -/ |
5 | | -namespace ToString --# |
| 5 | +import Lean --# |
6 | 6 |
|
7 | | -structure Point (α : Type) where |
8 | | - x : α |
9 | | - y : α |
| 7 | +/-- 標準ライブラリの `List` を真似て作った自前のリスト -/ |
| 8 | +inductive MyList (α : Type) where |
| 9 | + | nil : MyList α |
| 10 | + | cons (hd : α) (tl : MyList α) : MyList α |
10 | 11 |
|
11 | | -def origin : Point Int := ⟨0, 0⟩ |
| 12 | +namespace MyList |
12 | 13 |
|
13 | | --- 文字列補完により文字列に変換しようとしても、 |
14 | | --- 最初はどう変換したらいいのかわからないのでエラーになる |
15 | | -/-- |
16 | | -error: failed to synthesize |
17 | | - ToString (Point Int) |
18 | | -Additional diagnostic information may be available using the `set_option diagnostics true` command. |
19 | | --/ |
20 | | -#guard_msgs (error) in #check s!"{origin}" |
21 | | - |
22 | | -/-- `ToString` のインスタンスを登録する -/ |
23 | | -instance : ToString (Point Int) where |
24 | | - toString p := s!"Point: ({p.x}, {p.y})" |
| 14 | + variable {α : Type} |
25 | 15 |
|
26 | | --- これで文字列に変換できる |
27 | | -/-- info: "Point: (0, 0)" -/ |
28 | | -#guard_msgs in #eval s!"{origin}" |
| 16 | + /-- リストをリストらしく `"[a₁, a₂, ..., aₙ]"` という文字列に変換する |
| 17 | + **注意**: `ToString.toString` と紛らわしいことがあるので `protected` で修飾している |
| 18 | + -/ |
| 19 | + protected def toString [ToString α] : MyList α → String |
| 20 | + | nil => "[]" |
| 21 | + | ls@(cons _hd _tail) => |
| 22 | + "[" ++ helper ls ++ "]" |
| 23 | + where |
| 24 | + /-- 外側の括弧抜きでリストの中身を `,` でつないで表示する -/ |
| 25 | + helper : MyList α → String |
| 26 | + | nil => "" |
| 27 | + | cons hd .nil => toString hd |
| 28 | + | cons hd tail => toString hd ++ ", " ++ helper tail |
29 | 29 |
|
30 | | -/- ## Repr と ToString |
| 30 | + instance [ToString α] : ToString (MyList α) where |
| 31 | + toString := MyList.toString |
31 | 32 |
|
32 | | -[`Repr`](./Repr.md) のインスタンスはないが、`ToString` のインスタンスはあるという状態で `#eval` しようとすると、`Repr` の代わりに `ToString` のインスタンスが使用されます。`Repr` のインスタンスを与えればそちらが優先して使用されます。-/ |
| 33 | + -- `toString` が正しく動作しているかテスト |
| 34 | + #guard (toString <| MyList.cons 1 (MyList.nil)) = "[1]" |
| 35 | + #guard (toString <| MyList.cons 1 (MyList.cons 2 (MyList.nil))) = "[1, 2]" |
33 | 36 |
|
34 | | -/-- info: Point: (0, 0) -/ |
35 | | -#guard_msgs in #eval origin |
| 37 | +end MyList |
36 | 38 |
|
37 | | --- `Repr` のインスタンスを自動生成して登録する |
38 | | --- 以降は、`#eval` 時には `Repr` のインスタンスが使用される |
39 | | -deriving instance Repr for Point |
40 | 39 |
|
41 | | -/-- info: { x := 0, y := 0 } -/ |
42 | | -#guard_msgs in #eval origin |
43 | 40 |
|
44 | | -/- 逆に、`Repr` のインスタンスはあるが、`ToString` のインスタンスがないとき、`ToString` の代わりに `Repr` が呼び出されることはありません。エラーになります。-/ |
| 41 | +/- ## Repr と ToString の違い |
45 | 42 |
|
46 | | -structure Person where |
47 | | - name : String |
48 | | - age : Nat |
49 | | -deriving Repr |
| 43 | +[`Repr`](#{root}/TypeClass/Repr.md) と [`ToString`](#{root}/TypeClass/ToString.md) はどちらも項の表示に関わる型クラスですが、使い分けのルールが存在しており、それは `Repr` のドキュメントコメントに書かれています。 |
| 44 | +-/ |
50 | 45 |
|
51 | | -def david := Person.mk "David" 42 |
| 46 | +open Lean Elab Command in |
52 | 47 |
|
53 | | --- #eval はできる |
54 | | -#eval david |
| 48 | +/-- ドキュメントコメントを取得して表示するコマンド -/ |
| 49 | +elab "#doc " x:ident : command => do |
| 50 | + let name ← liftCoreM do realizeGlobalConstNoOverload x |
| 51 | + if let some s ← findDocString? (← getEnv) name then |
| 52 | + logInfo m!"{s}" |
55 | 53 |
|
56 | | --- `ToString` のインスタンスがないのでエラーになる |
57 | 54 | /-- |
58 | | -error: failed to synthesize |
59 | | - ToString Person |
60 | | -Additional diagnostic information may be available using the `set_option diagnostics true` command. |
| 55 | +info: A typeclass that specifies the standard way of turning values of some type into `Format`. |
| 56 | +
|
| 57 | +When rendered this `Format` should be as close as possible to something that can be parsed as the |
| 58 | +input value. |
61 | 59 | -/ |
62 | | -#guard_msgs (error) in #check s!"{david}" |
| 60 | +#guard_msgs in #doc Repr |
63 | 61 |
|
64 | | -end ToString --# |
| 62 | +/- `Repr` の出力は Lean のコードとしてパース可能なものに可能な限り近くなければならない、つまり Lean のコードとして実行可能であることが期待されます。一方で、`ToString` は単なる `String` への変換であってそのような制約はありません。 -/ |
0 commit comments