パターン
パターンとは | 引数がいくつあってもよい関数 |
パターンにマッチする式の検索 | 省略可能な引数とデフォルトの引数 |
パターンの参照名 | 省略可能な引数を持った関数の定義 |
パターンにおける式の型指定 | 繰返しパターン |
パターン適用範囲の制限 | 逐語的パターンマッチング |
多者択一型のパターン | 一般的な型の式に対応したパターン |
パターンシーケンス | 例:独自の積分関数の定義 |
平坦な関数と順不同な関数 |
ほとんどのパターンにおいて基本となるオブジェクトは,_(ブランクと呼ぶ)である.これは任意の式を表すものとされ,これは基本的な規定になっている.ほとんどのキーボードでは,アンダースコア記号_はダッシュ記号-と同じキーにある.
したがって,例えば,パターンf[_]は,形式f[anything]の式なら何でも表す.これに対して,パターンf[x_]は,f[anything]形の式なら何でも表すという点で同じだが,式 anything に参照名xを与えるという点で違う.名前が付くので,変換規則の右辺においてその引数を参照することができるようになる.
f[n_] | 名前をnとした任意の引数を取るf |
f[n_,m_] | 名前をnおよびmとした2引数を取るf |
x^n_ | 名前をnとした任意指数を持ったxのベキ |
x_^n_ | 任意指数を持った任意式 |
a_+b_ | 2式の和 |
{a1_,a2_} | 2式からなるリスト |
f[n_,n_] | 同じ2引数を取るf |
よくあるパターンの使い方に「式の構成の簡素化」がある.どういうことかを説明しよう.例えば,リストの特定要素2つを引数とする関数を検索するためのパターンを作るとする.まず,パターンをf[list_]としたとすると,リストの要素を抽出するにはPartのような関数を使う必要がある.しかし,この場合,引数は2つと判明しているので,代りにf[{x_,y_}]に対して定義を与えた方が通常より簡単で便利である.そうすれば,リストの要素をxとyの名前で直接参照することができる.さらに,fの引数が,2つの式のリストという形式でなければ,Wolfram言語は与えられた定義を使わない.
ここで理解してほしい重要な点は,Wolfram言語のパターンは任意構造を持った式のクラスを表す,ということにある.もしもパターンの構造が特定の式の構造と同じであるならば,パターンに現れるブランクを適当なオブジェクトで充填することで同じ式を得ることができる.したがって,パターンは式にマッチする.数学的に同じ値の式が2つあったとしても,式の構造が違えば,それらは同じパターンで表すことができない.
このため,例えば,パターン(1+x_)^2は,(1+a)^2と(1+b^3)^2等の式を表すことができるが,1+2a+a^2は表せない.後者は,数学的に(1+a)^2に等しいが,パターン(1+x_)^2と同じ構造を持ち合せていない.
一般論として,Wolfram言語で,構造的ではないが数学的に等価なパターンマッチングを行うことはほとんど不可能である.(1+a)^2や1+2a+a^2のような式であれば,ExpandやFactor等の関数を使い,式が数学的に等しいかどうかを決定することができる.しかし,「式の標準形への還元」で触れるように,任意な2つの数式が等しいかどうかを判定することができる一般的な方法は存在しない.
もうひとつの例を見てみよう.パターンx^_はx^2にマッチする.しかし,x^0ととらえることができても1にはマッチしない.(「省略可能な引数とデフォルトの引数」で説明するが,この問題に限り特別にマッチするパターンを記述することは可能である.)どのようなケースであっても,基本的に,Wolfram言語のパターンマッチングは構造的な等価性を判定するためにある.
認識してほしいもう一つの点として,Wolfram言語がパターンマッチングに使う構造は,FullFormにより記述された式の完全形による,ということがある.これがどういう意味を持つかというと,例えば,1/xは完全形でPower[x,-1]と書けるので,x_^n_のパターンにマッチする.しかし,x_/y_のパターンにはマッチしない.なぜなら,これは完全形ではTimes[x_,Power[y_,-1]]であるからである.先程も述べたように,この不一致の問題は「省略可能な引数とデフォルトの引数」で説明するパターン記述を使えば解消することが可能である.
Wolfram言語のパターンマッチングでは, の関係に代表されるような数学的に等しいかどうかの関係は調べられない.特定の構造的な性質に関した同値であるかが調べられる.例えば,可換則や結合則等の性質はパターンマッチングの考慮に入れられる.
ここでは,任意の式を表すことができるx_等のパターンオブジェクトを見てきた.他のチュートリアルでは,Wolframシステムで使われる,パターンで表された式のクラスを拡張したり,限定したりするための構造体を説明する.
Cases[list,form] | パターン form にマッチしたリスト list の要素を列挙する |
Count[list,form] | パターン form にマッチしたリスト list の要素の個数を返す |
Position[list,form,{1}] | パターン form にマッチしたリスト list の要素の位置を列挙する |
Select[list,test] | |
Pick[list,sel,form] | sel が form にマッチする list の要素を与える |
Casesのような関数はリストだけでなく式にも有効である.レベルを限定しておくことで抽出する部分を特定することもできる.
Cases[expr,lhs->rhs] | 変換規則の左辺 lhs にマッチする式 expr の要素を検索し,検索された要素に変換規則を適用し,結果を列挙する |
Cases[expr,lhs->rhs,lev] | 式 expr のレベル lev の部分を判定する |
Count[expr,form,lev] | 式 expr のレベル lev にある,パターン form にマッチした部分の個数を返す |
Position[expr,form,lev] | 式 expr のレベル lev にある,パターン form にマッチした部分の位置を列挙する |
Cases[expr,form,lev,n] | パターン form にマッチした,最初の n 個の部分だけを抽出する |
Position[expr,form,lev,n] | パターン form にマッチした,最初の n 個の位置を列挙する |
DeleteCases[expr,form] | パターン form にマッチした式 expr の要素を削除する |
DeleteCases[expr,form,lev] | lev で指定されたレベルにおけるパターン form にマッチした式 expr の要素を削除する |
ReplaceList[expr,lhs->rhs] | expr が lhs にマッチするすべての方法を求める |
特に変換規則を作る際は,パターンに名前を付けておき,それを参照することができるようにしておきたい.例えば,パターンに参照名 x_を付けておけば,パターンで抽出される式が実際に何であれ,その式の参照は x でできる.参照名は,例えば,変換規則の右辺で使われる.
このため,f[x_,x_]は,2引数を全く同じものとした式fしか表すことができない.これに対して,f[_,_]は,引数 x,y を必ずしも同じものとしないf[x,y]の形を持った式を表すことができる.
単一ブランクのパターンに限らず,任意形のパターンにも名前を付けることができる.任意パターン pattern を x と呼びたければ,x:pattern と入力する.この方法で名前を付けておけば,パターンがブランク以外の要素で構成された特別なものでも,変換規則の右辺で参照できるようになる.
パターンでも型の限定ができる.例えば,パターンを_h や x_h とすれば,頭部が h の式だけを検索対象にすることができる.整数型のパターンに限定するなら,_Integerとすればよいし,リスト型にするなら_Listと指定すればよい.
Wolfram言語は,パターンに制約条件を指定するための一般化された機構を提供している.単に,パターン記述の後に書式/;condition の条件を加えればよい.そうすると,制約条件がTrueになる場合に限り,パターンを適用する.ここで,記号/;はスラッシュ・セミと読み,その意味は「何々の,場合に限り」と解釈する.
pattern/;condition | 条件が満たされたときのみマッチするパターン |
lhs:>rhs/;condition | 条件が満たされたときのみ適用する変換規則 |
lhs:=rhs/;condition | 条件が満たされたときのみ適用する定義 |
/;は,個々のパターンだけでなく,:=の関数定義式や:>の変換規則にも使える.そのときも,式や規則の末尾に書式/;conditionを使い制約条件を加えることで,特定の条件が満たされるときだけに定義や変換規則が適用されるようにすることができる.ただし,注意点として,この/;条件は,通常,=の定義や,->の変換規則に使ってはならない.「即時的な定義と遅延的な定義」で述べるように,これらの式は直ちに評価されてしまうからである.
パターンと変換規則を組み合せて設定する際,式によっては,/;の制約条件を加える位置を選択することができる.例えば,規則の右辺に lhs:>rhs/;condition という形式で/;の条件を加えることも,左辺に lhs/;condition->rhs という形式で加えることもできる.さらに,左辺 lhs の内部に条件を挿入することも可能である.ただし,制限事項が1つある.それは,制約条件が付加されたパターンの記述において,すべてのパターンの参照名が明記されている必要がある,という事項である.これがないと,実際に制約条件を評価する際に,必要な参照名がまだパターンマッチングのプロセスに組み込まれていないという状況に陥ってしまい,制約条件の評価が続けられなくなってしまう.そうなると,パターンマッチングから参照したはずのオブジェクトは使えなくなるので,代りに,変数には大域的な値が適用されることになる.
例を見てみよう.f[x_,y_]/;(x+y<2)で示される制約条件は,f[x_,y_]のパターンマッチングから得られる変数x,yを必要とする.しかし,f[x_/;x+y<2,y_]における制約条件では,パターンマッチングから取得したyではなく,その大域的な値が適用される.
適切な参照名がパターンに与えられていれば,なるべく小さいパターンを選び,そこに/;の制約条件を適用するようにしておくと検索効率を向上させることができる.その理由は,パターンマッチングはパターン式の先頭から末尾に向かって要素の1つずつに対して行われるので,/;の制約条件が早く見付かれば見付かるほど候補を早く絞り込めるからである.
/;を使いパターンと変換規則を設けるときは,特定の性質や型を持つ数や式に限って適用可能になるようにするのが普通である.Wolfram言語には式の性質を識別するための組込み関数が用意されているので,それらを使い判定作業を行うとよい.組込み関数には,英語の「質問」を意味する単語「Question」から取ったローマ字Qで終る名前が付いているので分かりやすいだろう.
IntegerQ[expr] | 整数 |
EvenQ[expr] | 偶数 |
OddQ[expr] | 奇数 |
PrimeQ[expr] | 素数 |
NumberQ[expr] | 数 |
NumericQ[expr] | 数値 |
PolynomialQ[expr,{x1,x2,…}] | x1, x2, …の多項式判定 |
VectorQ[expr] | ベクトル判定 |
MatrixQ[expr] | 行列判定 |
VectorQ[expr,NumericQ] , MatrixQ[expr,NumericQ] | |
数判定付きベクトル判定(数判定付き数行列判定) | |
VectorQ[expr,test] , MatrixQ[expr,test] | 関数 test がすべての要素にTrueを与える行列 |
ArrayQ[expr,d] | 深度が d と同じである完全配列 |
IntegerQ[x]のような関数は,x が明示的な整数かどうかを判定する.x∈Integersのような推定の場合,Refine,Simplifyあるいは関連関数を使って,記号変数 x についての推測をすることができる.
SameQ[x,y] または x===y | x と y は等しい |
UnsameQ[x,y] または x=!=y | x と y は等しくない |
OrderedQ[{a,b,…}] | 標準的な並び順でリスト要素 a, b, …が配置されているかどうかを判定する |
MemberQ[expr,form] | 式 expr の要素に form にマッチするものがあるかどうか |
FreeQ[expr,form] | 式 expr の要素に form がないかどうか |
MatchQ[expr,form] | 式 expr がパターン form にマッチするかどうか |
ValueQ[expr] | 式 expr に特定値が定義されているかどうか |
AtomQ[expr] | 式 expr が部分式を持たない最小単位のものかどうか |
pattern?test | 判定 test の判定結果をTrueとする式だけにパターンを適用する |
条件構築 pattern/;condition を使うことで,パターン名を含む条件を評価させ,適合するものがあるかどうかを判定させることができる.これに対して,条件構築 pattern?test を使うと,任意関数 test が pattern によりマッチングされた式全体に適用され,適合するものがあるかどうかが判定される.場合によっては,/;の代りに?を使った方がよりコンパクトな形の定義にすることができる.
Exceptはパターンを引数として取ることができる:
Except[c]は,c 以外の「あらゆるもの」にマッチする,ある意味できわめて一般的なパターンである.場合によっては,patt にはマッチするが c にはマッチしない式に限定するExcept[c,patt]を使わなければならないこともあるだろう.
択一選択型のパターンを構築するときは,すべてのパターン候補に対して同じ名前を使うようにする.(a[x_] b[x_])のようなパターンが式にマッチするとき,オブジェクトxに対応する確定した式が必ずある.これに対して,(a[x_] b[y_])のようなパターンでマッチさせようとすると,xまたはyに対応する確定した式はあるが,対応しないものはSequence[ ]となる.
PatternSequence[p1,p2,…] | p1,p2,…にマッチする引数のシーケンス |
空のシーケンスPatternSequence[]はオプショナルの引数を指定するのに便利なことがある.
つまり,Wolfram言語のパターンマッチングでは,式 x+y と式 y+x は等しいものとされる.このため,g[x_+y_,x_]のようなパターンは,g[a+b,a]だけでなく,g[a+b,b]にもマッチする.
Wolfram言語が,パターンマッチングでPlusやTimes等の順不同性や可換性の関数を抽出するとき,マッチするかどうかを見るために,引数の可能な限りの組合せが判定される.場合によっては,マッチする引数の組合せが複数あることがある.そのような場合は,最初に見付かった組合せが採用される.例えば,h[x_+y_,x_+z_]は,x→a,y→b,z→bまたはx→b,y→a,z→aのどちらの代入を行ってもh[a+b,a+b]にマッチすることができる.実際は,x→a,y→b,z→bが最初に試されるので,それにマッチした組合せが使われる.
ReplaceListを使い,マッチ可能なすべての並び順を表示させる:
「属性」で説明するように,Wolfram言語では関数に特別な属性を割り当てることができるようになっている.属性を与えることで,評価するときやパターンマッチングをするときにこれらの関数がどう取り扱われるべきかを指定することができる.例えば,任意関数に順不同の属性Orderlessを割り当てておくことで,パターンマッチングにおいてそれらの引数を可換性または対称性を備えたものとして扱わせることができ,またマッチさせるために引数を再構成させることができる.
Orderless | 可換性の関数 f[b,c,a]等は,f[a,b,c]に等しいものとする |
Flat | 結合性の関数 f[f[a],b]等は,f[a,b]に等しいものとする |
OneIdentity | f[f[a]]等は,a に等しいものとする |
Attributes[f] | f に割り当てられている属性をすべて列挙する |
SetAttributes[f,attr] | f に属性 attr を割り当てる |
ClearAttributes[f,attr] | f から属性 attr を除去する |
PlusやTimes等の関数は,順不同性の他に平坦性や結合性の属性も兼ね備えている.このため,それらの引数は,丸カッコでどう「まとめ」直しても等価なままである.例えば,x+(y+z)は,x+y+zに等しいものとされる.
Wolfram言語が関数にある変換規則を適用できるのは,通常,その変換規則にあるパターンが関数の引数を網羅しているときに限る.しかし,関数が平坦のときは,すべての引数が網羅されなくても,場合によっては変換規則を適用することができる.
平坦でない普通の関数において,x_等のパターンは同じ関数が持つ引数だけにマッチする.しかし,平坦で,f[a,b,c,…]の構成の関数では,x_は,f[b,c]等の引数の列に相当するオブジェクトにマッチすることができる.しかし,平坦性の関数でx_が引数にマッチした場合,それがマッチしたオブジェクトは,引数 a なのか,それとも f[a]なのか,との疑問が出る.Wolfram言語は,関数が属性OneIdentityを備えている場合は前者を取る.そうでない場合は,まず後者を使おうとするが前者に頼っている.
Plus,Times,Dotはすべて恒等性の属性OneIdentityを持つ.このため,例えば,Plus[x]は x に等しい.ただし,数学的なオブジェクトを表すときは,多くの場合,属性OneIdentityを持たない単なる平坦な関数として使えた方が便利になる.
これを行うには,複数のブランク記号を使う.単一ブランクによるパターン,例えば,x_は,1つのWolfram言語式だけしか表せない.これに対して,x__のような二重ブランクは,式がいくつあってもそれらをすべて表すことができる.
「二重ブランク」__は,1つもしくは複数の式からなる式の列を表す.「三重ブランク」___は,ゼロもしくはそれ以上の式からなる式の列を表す.ただし,三重ブランクをパターンに使うときは特に注意が必要である.無限ループに陥る危険性があるからである.例えば,p[x_,y___]:=p[x] q[y]と定義したとする.ここで今,p[a]をタイプすると,yがゼロ要素により列の要素に繰り返しマッチしてしまうことから,無限ループに陥ってしまう.このため,ゼロ要素のケースを含める必要がある場合を除いて,三重ブランクではなく二重ブランクを常に使うようにする.
_ | 1つの式を表す |
x_ | 1つの式を表し,参照名を x とする |
__ | 1つ以上の式からなる式の列を表す |
x__ | 1つ以上の式からなる式の列を表し,参照名を x とする |
x__h | すべて h を頭部とした式である式の列を表す |
___ | ゼロ成分のケースも含める |
x___ | 参照名を x とするゼロあるいは1つ以上の式からなる式の列を表す |
x___h | すべての頭部が h であるゼロあるいは1つ以上の式を表す |
「平坦な関数と順不同な関数」で触れたが,PlusやTimesのような平坦性の関数では,Wolfram言語は,引数がいくつあってもそれらを自動的に扱うことができる.このため,特別に二重ブランクや三重ブランクを使う必要はない.
多重ブランクを使うと,特定の式にマッチする組合せが複数生じることがよくある.Wolfram言語は,デフォルトで,最も短くなる引数の列を,パターンマッチングの最初の多重ブランクに割り当ててくれる組合せをまず試すようになっている.この順序は,パターンの部分をLongestかShortestでラップすることで変更することができる.
ReplaceListを使いパターンを変えることで,いろいろな組合せを列挙することができる:
場合によっては,引数が省略されたなら「デフォルト」の引数が自動的に代替されるように関数定義を設定しておきたい.パターン x_:v は,省略可能なオブジェクトを表す.実際に省略されると,引数には v があてがわれる.
標準的なWolfram言語関数の中には,引数のデフォルト値が組込み済みのものがある.わざわざ x_:v の書式でデフォルト値を指定する必要はない.x_.を付加しておけば,組込み済みのデフォルト値を使ってくれる.
加法式にいくつ項があろうと,Plusは平坦な関数であるから,x_+y_のようなパターンは,その式にマッチすることができる.しかし,このパターンは,a等の単一項はマッチすることができない.ただし,パターンx_+y_.は省略可能な部分を含んでいるので,x_とy_の両方を持つ項,または,yを0とした単一項x_を持つ項からなる明示的な加法式にマッチすることができる.
PlusやTimes等の標準的なWolfram言語関数は,引数のための,あらかじめ組み込まれたデフォルト値を備えている.また,ユーザ定義の関数についてもデフォルト値を設けておくことができる.詳しくは,「パターン」を参照のこと.
オプショナルの引数にデフォルト値を割り当てない方が便利な場合もある.そのような引数はPatternSequence[]で指定することができる.
pPatternSequence[] | デフォルト値のないオプショナルのパターン p |
第1の方法では,引数の位置に従い個々の引数の重要度を決定し,重要でないものから省略されたものとみなし除外する.そして,それらをデフォルト値に置き換える.Wolfram言語のほとんどすべての組込み関数では,この方法が使われ末尾の引数から除外されていく.例えば,平坦化を行うための組込み関数Flatten[list,n]では,第2引数は与えられなくてもよい.与えられなければデフォルト値であるInfinityが代りに使われる.
第2引数は省略可とする.デフォルト値Infinityが使われる:
組込み関数における省略可能な引数への対応で取られる第2の方法は,省略可能な引数に固有の参照名を与えておき,変換規則を使うことで,引数が省略されたときに取られる代替値を決めておく,という方法である.この方法は,Plotのような非常に多くの省略可能な引数を持った関数で特に便利になる.実際に関数を使うときは,限られた数の引数を与えるだけで関数は機能する.
通常の手順としては,特定の関数に与えられる引数に続ける形で適切な変換規則を含めることで,「参照名付き」の省略可能な引数を指定することができる.例えば,参照名付きの省略可能な引数Joinedに対する設定を指定する規則Joined->Trueは,ListPlot[list,Joined->True]と表すことができる.
f[x_,OptionsPattern[]]:=value | 参照名付きの省略可能な引数を持たない,あるいは持つ関数に対する通常の定義 |
OptionValue[name] | 関数に与えられている,参照名付きで省略可能な引数の値 |
FilterRules[opts,Options[name]] | opts の中の規則で関数 name によりオプションとして使われるもの |
FilterRules[opts,Except[Options[name]]] | |
opts の中の規則で関数 name によりオプションとして使われないもの |
次によりNDSolveで使われるメソッドと,プロットの色が変更される:
x__等の多重ブランクを使うことで,複数の任意式からなる列を含んだパターンを構築することができる.また,Wolfram言語のパターンの繰返し演算子である..と...を使うことで,同じ形が任意回数繰り返し現れるパターンを構築することもできる.例えば,f[a..]は,f[a],f[a,a],f[a,a,a]のどの形の式でも表すことができる.
p.. または Repeated[p] | 1回以上繰り返されるパターンあるいはその他の式 |
Repeated[p,max] | 最高 max 回まで繰り返されるパターン |
Repeated[p,{min,max}] | min 回ないし max 回繰り返されるパターン |
Repeated[p,{n}] | 厳密に n 回繰り返されるパターン |
Verbatim[expr] | 式を記述通りにマッチしなければいけないものにする |
「パターンとは」で述べたオブジェクトを組み合せることで,各種の式に対応可能なパターンを構築することができる.ただし,すべての場合において,作成するパターンがどんなものであろうと,それは,FullForm(完全形)によるWolfram言語内部で有効な式の構造を表す必要がある.
一般的ではあるが,式の種類によっては,それらが標準の出力表記で表示されるとき,Wolfram言語内部で使われる完全形とは違う表記が使われる.それでも,パターンの設定は,常に内部表記に従って行う必要がある.
n_Integer | 整数の型を持ち参照名が n のパターン |
x_Real | 実数の型を持ち参照名が x のパターン |
z_Complex | 複素数の型を持ち参照名が z のパターン |
Complex[x_,y_] | x+iy 形式の複素数パターン |
Complex[x_Integer,y_Integer] | 実数部分と虚数部分がともに整数である複素数パターン |
(r_Rationalr_Integer) | 有理数か整数の型を持ち参照名が r のパターン |
Rational[n_,d_] | の形の分数パターン |
(x_/;NumberQ[x]&&Im[x]==0) | 実数(数の型は不問)のパターン |
(x_/;NumberQ[x]) | 数のパターン |
これらが異なる完全形となっているため,x_+Iy_では複素数は検索できない:
「記号計算」で触れたが,Wolfram言語内部で,すべての代数式は,基本的にベキの積の和からなる標準形に変換される.さらに,比は,分母項を負の指数としたベキの積に変換される.また,差は,負符号を付加された項からなる和に変換される.このため,代数式用のパターンを作る際は,この標準形に従って構築しなければいけない.この形は,多くの場合,Wolfram言語により画面に表示される代数式の形とは違う.いずれにしても,式が何であっても,FullForm[expr]を使うことでその完全形を前もって確認することができる.
x_+y_ | 2つ以上の項の加法式 |
x_+y_. | 単項式または多項式 |
n_Integer x_ | 整数型に限定された乗数を持つ式 |
a_.+b_.x_ | 形が a+bx の一次式 |
x_^n_ | n≠0,1とした xn |
x_^n_. | n≠0とした xn |
a_.+b_.x_+c_.x_^2 | 非ゼロ線形項からなる二次式 |
x_List または x:{___} | リスト |
x_List/;VectorQ[x] | サブリストを持たないベクトル |
x_List/;VectorQ[x,NumberQ] | 数ベクトル |
x:{___List} または x:{{___}...} | リストのリスト |
x_List/;MatrixQ[x] | サブリストを持たない行列 |
x_List/;MatrixQ[x,NumberQ] | 数行列 |
x:{{_,_}...} | ペア要素のリスト |
数学形式 | Wolfram言語における定義 |
integrate[y_+z_,x_]:=integrate[y,x]+integrate[z,x] | |
( は に独立) | integrate[c_y_,x_]:=c integrate[y,x]/;FreeQ[c,x] |
integrate[c_,x_]:=cx/;FreeQ[c,x] | |
,
| integrate[x_^n_.,x_]:=x^(n+1)/(n+1)/;FreeQ[n,x]&&n!=-1 |
integrate[1/(a_.x_+b_.),x_]:=Log[ax+b]/a/;FreeQ[{a,b},x] | |
integrate[Exp[a_.x_+b_.],x_]:=Exp[ax+b]/a/;FreeQ[{a,b},x] |
Plusの結合性により,総和の中にいくつの項があろうとも線形性の関係が機能する:
Wolfram言語は各積の各項がFreeQの条件を満足するかどうか,すなわち取り出せるかどうかをテストする: