Blog株式会社マネーフォワード公式開発者向けブログです。技術や開発手法、イベント登壇などを発信します。サービスに関するご質問は、各サービス窓口までご連絡ください。真理値エンジニアの澤田です。Rails)コードで気になった箇所の問題点やそこから発展して関連事項を議論しています。文字列の生成と検証を考察しました。記事に言及してもらったり、コメントをもらったりして、励みになっています。今回は真理値について考察します。題材とするコードは、社内のGitHubプルリクエストで実際に見かけたコードから問題点に関係する部分を抽出し、抽象化したもので、見かけたものそのままではありません。今回は真理値の周辺を考察します。プログラミングにおいて真理値が何のためにあるかといえば、時に論理演算を施され、最終的に制御構造の条件部やメソッドに渡される引数やメソッド内のフラグなどとなって、場合分けに使われることがほとんどだと思います。従って、今回の真理値の考察には場合分けについての議論が多く登場します。Rubyの論理演算で「偽」とされる値はfalseとnilだけです。空文字列や、空配列、零などといったオブジェクトを実質的に偽のようにして場合分けしているコードも見かけます。このような場合分けの中には必要なものも必要でないものもあります。反対に、オブジェクトの値falseやnilを実質的に「真」と見なし、メタな評価基準を導入して偽を判定する必要のある場面もあります。このような、ユースケースごとの実質的な真理値のずれもまた真理値を考察するにあたっての大きな話題です。本稿では、次の「真理値の定義」と「述語メソッド」の節で概念的なことを整理して、その後の節で問題のあるケースを見ていきます。本稿では、「真理値」という言葉を、Rubyオブジェクトの値を直接に指すものでなく、そのオブジェクトの論理演算や制御構造での振る舞いを表すものとして用い、「偽」か「真」の値を取るものとします。以下で、Rubyと他のプログラミング言語における真理値の定義を考察します。Rubyの真理値Rubyの論理演算ではfalseとnilだけが偽の真理値で、他は真です。これには次のような理由があると考えられます。Rubyの文字列や、配列、ハッシュなどはミュータブルであり、同一のインスタンスが空になったり空でなくなったり変化することがあります。falseそこで、もしRubyで空文字列や、空配列、空ハッシュを偽と定めるとすると、1つのインスタンスの真理値がプログラムの実行途中で変わり得ることになります。Implementation)のソースコードを見る限りでは、真理値の判定はインスタンスの同一性に基づいて行われています。頻繁に行われる論理演算はインスタンスの状態を考慮しないで行うという暗黙の原則があることが推測され、そのため空文字列や、空配列、空ハッシュはRubyで偽とし得なかったと考えられます。すると、Rubyで偽と定められ得るオブジェクトはイミュータブルなものに限られます。0.0など)については、偽として扱いたい動機があまりなかったようです。零を偽とすることが検討され、結局その案が取り入れられなかったことが過去にあったそうで、その経緯がRuby開発者の方によってまとめられています。1他のプログラミング言語での偽を広く定める真理値プログラミング言語によって、空文字列や、空配列、零などを偽と定めることがあります。これらのオブジェクトを特徴付ける性質を挙げるとすれば、「加算」と呼べるある演算に関して単位元になっていることです。Rubyではこれらを偽としませんが、Rubyでもこれらのオブジェクトは然るべき加算メソッドの単位元です。3しかし、単位元であることがどうして偽とすることにつながるのか直ちに明確ではありません。面白いことに、複数のオブジェクトを偽と定めた場合、それらのオブジェクトは論理和に関して、左単位元であるものの、(右)単位元でなくなります。実際にRubyでは、falseやnilは||の左単位元ですが、以下の結果から分かるように、(右)単位元でありません。nil空オブジェクトや零と偽として扱う理由が明確でない一方で、逆に偽であるnilを空オブジェクトや零として扱うためのメソッドがあります。(0+0i)これらのメソッドのユースケースを見ると、空オブジェクトや零で表されるべき値を特に理由もなくnilとして保持していて、後で空オブジェクトや零にするという用法が多いような気がします。その一例は後の節で出てきます。述語メソッドレシーバーによって論理演算の偽と真のどちらの値も返すメソッドで、真の値が比較的簡単なものを述語メソッドと呼び、メソッド名の末尾に?を付ける規約があります。この節では、述語メソッドについての理解を深めるために、いくつかの観点から分類してみます。述語メソッドは返り値の組み合わせによって3種類あります。true述語メソッドの大半はここで「狭い意味での述語メソッド」と呼んだものに当たり、例はString#match?やNumeric#zero?です。同じパターンの返り値を取るもので、?で終わる形をとっていないメソッドとしてはString#==などがあります。「広い意味での述語メソッド」と呼んだものについては、知名度が低かったり、述語メソッドとして認識していない人もいますが、標準Rubyにもあります。File#size?やNumeric#nonzero?などがそうです。返り値が同じパターンで、?で終わる形をとっていないメソッドとしてはString#=~などがあります。広い意味での述語メソッドは真の値(簡単なオブジェクト)を複数持ちます。簡単なオブジェクト」の値の範囲内で行われ、例外的な場合を表すメタな値としてnilがあると考えると良いでしょう。述語メソッドの中には、レシーバーが偽やそれに準ずるもの(空オブジェクトなど)であるときに真を返すものがあります。Symbol#empty?これらのメソッドは真理値を反転するため、注意が必要です。&.との併用は大抵間違っています。空オブジェクトと空でないオブジェクトの3つの場合を取り得る変数errorsを次のように前者2つ対3つ目で場合分けしようとしているコードを見かけました。errors&.empty?しかし、想定した結果を出すことに失敗しています。実際には次のような結果が返ります。偽empty?が否定を持つために、偽とされるべき空オブジェクトに対して真を返し、&.empty?をそのまま通過するnilと逆側の真理値になってしまったためです。to_hを使うことで、初めに想定した結果とは真理値が逆になりますが、想定通りの場合分け(グルーピング)をすることが出来ます。肯定のifの代わりに否定のunlessを使えば、想定通りの制御構造になります。偽あるいは、ハッシュの場合に限っては、否定を含まないHash#any?を使って真理値を反転せずに空かどうかを調べることが出来ます。その場合には、真理値が反転しないので、&.を使うことによって、nil値の場合も含めて1つ目の表で想定した通りの真理値が得られます。true配列の場合にArray#any?を使うと、同様に真理値は反転しませんが、「空配列対空でない配列」ではなく「真オブジェクトを含まない配列対含む配列」の区別になり、違ったものになってしまうので、注意して下さい。true評価レベルレシーバーをどのレベルで評価するかによって、述語メソッドは3つに分類できます。本稿では評価のレベルを次のように呼ぶことにします。「クラス判定」をする述語メソッドとは、1つのインスタンスに対して返り値が常に一定で、さらにその返り値がクラスの全インスタンスに対して同じものを言います。これはクラスへの所属を調べるもので、次のものがあります。これらはメソッド名から想像されるインスタンスの数学的な同値関係に関係がなく、所属クラスを判定します。Complexクラスのインスタンスであり、integer?やreal?に対して異なる値を返します。falseしかも、real?は「Complexクラスのインスタンスでない」という所属関係の否定を表すところがややこしさを増しています。所属」という言い方になってしまったからだということが推察されます。本稿で「インスタンス判定」をする述語メソッドとは、1つのインスタンスについて返り値が決して変わらず、その返り値がインスタンスによって異なるものを言います。Float#positive?Float#nan?Integer#even?Integer#odd?これらのレシーバーは、全てイミュータブルなオブジェクトです。本稿では「状態判定」をする述語メソッドは、1つのインスタンスについて、その状態によって返り値が変わるものを指しています。空オブジェクトに対するガード必要がないのに空オブジェクトを条件分岐したり空オブジェクトからガードしているコードを何度か見ました。「ガード」というのは、それに続くコードで問題を起こすと考えられる場合をコードの本流から隔離する制御構造をいいます。arrayが空配列のときにメソッドの途中で脱出する次のようなコードを見ました。array.empty?array.each{...}これにより、arrayが空の場合に、次の行のeachが適用されなくなります。次のような場合分けも同様の働きをする構造です。array.select!{...}end空配列も配列なので、空でない配列に対して呼び出されるインスタンスメソッドは空配列に対しても呼び出されます。空だからということでメソッド未定義エラーは発生しません。空配列には要素はないので、イテレーションしても、ブロックは実行されません。上記のようなガードや制御は冗長で、不必要にコードを複雑にしています。次のコードで足ります。array.each{...}array.select!{...}ちょっとした変種として、次のようなものもありました。これも過剰な場合分けです。偽に準じる空オブジェクトは分けておかなければならないという意識が働いてしまうのでしょうか。nilので、次のコードで十分です。array.find{...}文字列でこれに対応する場合が次の例です。string[regex]と等価です。同じ論理の繰り返し強く主張を持って次のように書いているコードを見かけたことがあります。c].include?(:a)二重否定!!は偽オブジェクト対真オブジェクトをfalse対trueに写像するためによく使われます。1つ目の!で偽オブジェクトをtrueに、真オブジェクトをfalseに写し、2つ目の!でfalseとtrueを入れ替えます。この例で使われているArray#include?のようなメソッドは、そもそもfalseかtrueしか返さない狭義の述語メソッドなので、その値に対して改めて真理値で場合分けしてfalseとtrueを返すようにしたり、二重否定を経由して同じfalseとtrueに戻ってくることには意味がありません。これを書いた人にこのことを指摘したら、頑なに拒絶されてしまったのが残念でした。他のプログラミング言語での習慣を引きずってしまったのかも知れません。いった書き方は、折角のRubyの簡潔さを否定するものです。次のように書けば済みます。c].include?(:a)falseとtrue以外を返す広義の述語メソッドには、大抵の場合、似たような働きをする狭義の述語メソッドがあります。String#=~の代わりにString#match?を使ったり、File#size?の代わりにFile#exist?を使えば済むことです。代替のない広義の述語メソッド、例えばFile.world_readable?については、このまま論理演算に使っても一切不都合はありませんが、真理値を返すメソッドを新たに定義する中で使うために、falseとtrueを返すことにこだわるなら、上のような方法を使うことにいくらかの正当化の余地はあります。Railsの述語メソッドを適用し、それをそのまま制御構造の条件部分で使っている次のようなコードを見ました。foo.present?present?は偽や空オブジェクトなどをfalseに、それ以外のオブジェクトをtrueに変換します。trueここで、変数fooは、present?によって真理値が真から偽に変換されるような値(空オブジェクトなど)を取る可能性のないものでした。Railsを使わないコードでいうと、前の節で言及した!!を使った次のようなコードと大体同じことをしています。!!fooこのような例の場合、上の節で述べたような、もとからfalseやtrueで値の変わらない写像とは異なり、値は変更されます。真理値には変更がない(偽は偽へ、真は真へと写される)ので、present?や!!を使わなかった場合と論理演算や条件分岐の結果に違いはありません。従って、これらも無駄です。無駄なものはなくしましょう。foo&.に置き換えられる制御構造fooが整数を表す文字列かnilであり、falseになり得ない状況で、次のようなコードを見ました。foofooがnilである場合に返り値にnilが欲しい場合でした。0によって0が与えられてしまうので、そうは出来ません。RubyのNull条件演算子&.の存在は広く知られていますが、これをメソッド未定義エラーの回避にしか活用していない人がいます。Railsのtryメソッドの代替もしくは後継にしか思っていないのかも知れません。そのような意識はきっぱり捨てるべきです。ここの例のような場合に&.は有効です。foo&.to_ifooがnilの場合には、&.によりto_iの適用がスキップされ、nilが返ります。false)と書けば、fooがnilであるときばかりでなく、他の文字列以外のオブジェクトであるときや整数を表さない文字列の場合にもnilを返すことが出来ます。次のように、メソッド連鎖に関係して&.を中途半端に使っている例があります。nil1つ目のメソッドにのみ&.を適用し、その後は諦めてしまったのでしょう。諦めずに最後まで&.を使いましょう。foo&.bar&.baz無用なデフォルトのnilこういうコードを良く見ます。nilにしておいて、その後、nilを使うことなく、本来意図したデフォルト値default_barに置き換えています。default_barが空オブジェクトや零の場合が、前の節で言及した、空オブジェクトや零で表されるべき値をnilとして保持しておき、後で空オブジェクトや零に置き換えるという場合です。多くの場合、nilはメタ的な値を表し、通常のケースでは使わない値なので、nilを割り当てておけば、明示的に値を与えた場合と干渉しないという考えなのでしょう。一時的にでもnilという値を与えておかなければならないのか分かりません。初めから、意図したデフォルト値をメソッド定義の引き受け部に指定しておけば済むことです。...end制御構造から暗黙的に与えられるnil多くの制御構造やメソッドで、随意的な引数が省略されたときやある条件分岐の場合に、nilが返されます。このようなRubyの仕様に頼らずに不必要にnilに言及している例を挙げます。nil条件some_conditionを満たさないときはnilを返したいという意図ですが、ifが条件を満たさないときにnilを返すことを使って、次のように書けます。nextでは、引数がないときにはnilが返されます。他の値を返す場合との対比を明示的に示すなどの理由がない限り、省略しましょう。return偽を広く扱う論理nilやfalseに加えて空オブジェクトを偽と同様に扱う場合を見ます。変数にnilが付与されようとするときに、代わりに空文字列を与えるコードを見ました。その変数は後に文字列に埋め込むときだけに使われます。""..."...#{string}..."ここで空文字列という特別な文字列をnilという偽の代わりに使っていて、つまり、空文字列を偽のように使っている訳です。""により空文字列が得られて同じ結果になるので、わざわざnilを空文字列に置き換えておく必要はありません。some_method..."...#{string}..."空配列に注意が必要な場合ときに、空オブジェクトの場合に気を使わなければならないこともあります。injectで初期値を省略すると、イテレーションの最初の値が初期値として使われます。6レシーバーが空配列の場合に初期値を省略すると、イテレーションが行われず、初期値が分からないので、nilが返ります。nilこれで良い場合は良いですが、1を返したい場合には、レシーバーが空配列になり得るかどうかを考えて初期値1を省略出来るか見極めないといけません。配列中の数値の和を計算したい場合には、専用のメソッドArray#sumを使えば、空配列を気にする必要はありません。空オブジェクトを他の真オブジェクトと区別して偽のように扱わなければならないときもあります。"でつなげて表示したいとしましょう。単純にjoinを使うと、次のようになります。"が続くこのような出力は不格好と考えられるでしょう。そこで次のようなコードを使うことになります。bar"このように、空オブジェクトを、いずれ他のオブジェクトとは異なる仕方で扱うのであれば、あらかじめ偽値のnilに置き換えておけばよいです。この例では、表示のステップなどで必要になった時にその場でするのではなく、空文字列を受け取った後の出来るだけ早い時点で、空文字列からnilに変換しておけば良いです。bar"後で特別な扱いをするのなら、早いうちにnilとして持っておいたほうが使い勝手が良いです。このことを示す次の例があります。...some_paramはユーザーから受け取った文字列パラメーターです。このsome_paramは、コードの至るところでsome_param.present?の形で制御構造の条件や論理演算の一部分として使われていました。Railsの述語メソッドです。空文字列の場合のsome_paramを偽として扱うのにも関わらず、空文字列のまま保持しているために、論理の随所にそのことを引きずってpresent?を適用しています。この場合も、出来るだけ早い時点で、空文字列からnilに変換しておけば、そのようなことから開放されます。Railsを使っている場合には、この目的のためにpresenceというメソッドがあります。これは、偽や空オブジェクトなどをnilに、それ以外のオブジェクトはそのままにしておくメソッドです。Railsを使っているならpresenceを使い、使っていないなら他の方法でこのようなパラメーターはできるだけ早いうちに変換しておきましょう。...偽を狭く扱う論理nilだけを偽として扱い、falseを真と同様に扱う場合を見ます。nilの区別が不必要な場合fooがfalse値を取らない状況でnilを明示的に場合分けしているコードをよく見ます。foo.nil?falseの可能性を考慮しなくていいのなら、nilとfalseを区別する必要はありません。次のコードで足ります。変数fooが随意的なパラメーターで、意味のある値としてfalseを取り得、明示的に値が与えられていない場合にnilを取るとき、明示的に値が与えられたかどうかを区別する必要があれば、nil?を使います。問題となっているオブジェクトの(真理)値からは場合分けに必要な情報が得られない場合があります。いう場合は、オブジェクトの値ではなく何らかのメタな情報にアクセスする必要があります。一度計算した値を2回目以降に呼び出したときに、再度同じ計算をしなくて済むように、初回に計算した値を保存しておいて、2回目以降にはその値に言及するだけにする技法があり、これは「メモ化」と呼ばれます。メモ化のつもりで次のように書いているコードに遭遇しました。calculate_fooこれは、次のコードの省略記法であり、ほぼ等価です。メソッド+などに基づく類似の省略形+=などとは展開のされ方が異なることに注意して下さい。メソッドでない||はここでは=よりもスコープが広くなっています。calculate_fooインスタンス変数@fooは未定義時にnilを返すので、1回目にこのコードが呼び出されるとcalculate_fooが評価され、@fooに代入されます。問題は2回目からです。ここで登場するcalculate_fooは、計算結果がnilになる可能性のあるものでした。@fooを1回目に計算した結果が真なる値であれば、2回目以降は論理和の短絡評価により@fooが返り、calculate_fooの計算や@fooへの代入が抑制されますが、1回目に計算した結果がnilであれば、2回目以降もcalculate_fooが計算され、@fooに代入されます。メモ化が半分しか機能していません。もとのコードを書いた人にこのことを指摘しても、初めは理解してもらえませんでした。このコードのパターンを、よく見かけるからといって、理解せずに決まり事のように使ってしまっていたのだと思います。@fooが偽となる可能性がない場合には、上のようなコードで構いません。@fooが未定義の場合のnil値と@fooがすでに計算されている場合の真値が論理和によって場合分けされます。ここの例のように@fooの計算結果が偽になり得る場合には、単なる論理和で@fooが一度計算されたのかどうか判別できません。@fooが未定義時のnilと計算した結果がnilになる場合が重なるので、@fooの値によるいかなる場合分けによっても@fooが計算済みかどうかを区別することがそもそも出来ません。この場合は、ずばり「インスタンス変数が定義されているかどうか」を調べるメソッドKernel#instance_variable_defined?で判定します。calculate_fooendなどとします。ちなみに、上で省略記法||=とその展開された形について、ほぼ等価と書きましたが、変数の初期化のタイミングに違いがあります。インスタンス変数@fooやグローバル変数$fooは、未定義のまま参照するとnilが返るので、省略形でも展開された形でも違いを観察できませんが、ローカル変数fooやクラス変数@@fooは未定義のまま参照するとエラーを発生させるので、これらを使った場合、展開された形で初期化することは出来ません。...ところが、省略記法を使うと、エラーが発生しません。"default"このように、||=は変数の初期化に関しては1つのトークンとして機能し、未定義により参照に失敗すると、直ちに値の付与に移行します。ややこしいことに、ローカル変数の初期化は字句解析時に行われてnilが与えられ、コードの評価とは関係ありません。ローカル変数が、字句の線的な順序に関して初めて登場するときに、それが値を付与される形であれば、評価時に未定義のままで呼び出されても、未定義エラーは起きません。従って、ローカル変数では、=が||よりも左側に来る次のような書き方も可能です。nilの初期化がされ、その後に(=の評価よりも前に)右辺のbazが評価中に呼び出されるからです。ハッシュのキーの存在Hash#[]をあるキーに対して呼び出して条件分岐しているコードをよく見かけます。hash[:baz]この例ではキーに対する値に関心があるのではなく、キーがハッシュ中にあるかどうかを調べようとしています。これが問題となる箇所で見かけた訳ではありませんが、この使い方には注意が必要です。ハッシュにキーが登録されていないときにHash#[]で値を呼び出すと、nilが返ります。従って、ハッシュにnilが値として保持されている可能性がある場合には、Hash#[]でハッシュの値を見ただけでは、nilが保存されているのかキーがないのか区別できません。nilまた、nilの可能性がなくてもfalseの可能性があるなら、少なくとも次のようにしてfalseとnilを区別しないといけません。hash[:baz].nil?しかし、nil?によって真理値を反転しているので、制御構造の条件が逆になり、ややややこしくなります。このような区別が問題になるときには、ずばり「ハッシュにキーが含まれているかどうか」を調べるメソッドHash#key?で判定します。false見かけた例は、次のように書けば、ハッシュの値がnilになるときにも使えます。述語メソッドを評価した値を変数に付与しておく場合に、その変数にも真理値を表すものであることをマーキングしたいことがあるようです。ところが、Rubyの仕様上、変数名を?で終わらせることが出来ません。そこで、代替として、英語のbe動詞を使ってマーキングしているのをよく見かけます。foo.empty?この例のように、be動詞の後に来る単語が名詞や、形容詞、前置詞ならいいのですが、これをむやみに適用して、次のように動詞などにまでbe動詞を付けているのを見かけます。bar.include?(baz)これは英語として酷いです。受動態や進行形にするわけでもないのに、動詞の前にbe動詞は付けられません。余りに多くこのような例を見ました。includeでよいと思います。これは筆者個人の考えですが、一般的にbe動詞を付ける必要がそもそもないのかも知れません。Rubyはダックタイピングを推奨しています。変数にも型はありません。いかなるオブジェクトも論理演算に使えるので、ブール型という概念の根拠が弱いです。変数が何を指し示しているのかはっきりしていれば、型、特に真理値を表すことをことさら強調する必要はないのではないでしょうか。それではなぜ述語メソッドには?を付けるのかという疑問が湧くかも知れません。「含める」というように、ある状態にしたり動作を行ったりするメソッドであると予測することだと思います。「含むのか」という問い合わせであることがはっきりします。ここで、述語メソッドに対応する、yesかnoかを問う種類の疑問文は、問題の述語が文末の疑問符に比較的近いことが多く、さらに文末が上がり調子になります。疑問符を付けたメソッド名と、対応する疑問文の結びつきが自然です。values_atなどに対応する、実のある内容を問う、疑問詞を使った疑問文では、問題の部分が疑問詞であったり疑問詞とくっついたりして文頭に移動し、さらに文末が上がり調子になりません。このことから、述語メソッド以外のメソッドに使われる述語に疑問符を付けて出来たメソッド名と、対応する疑問文との結び付きが悪いと考えられます。bar?だいたいそんなところから述語メソッドにだけ?を付けるようになったと筆者は推測します。一方で、変数の場合には、ある状態にしたり動作を行ったりするという作用がないので、メソッドの場合のように問い合わせの場合を区別する必要がありません。従って、?に相当するマーキングは不必要だと思います。DSLで用意されたbe動詞の乱用DSL、特にプログラマ以外の人も読むことが想定されているテストフレームワークには、コードを英語に近づけるために、メソッド名に細工したり、be動詞などをメソッドやメソッド名の一部として挿入できるようにしているものがあります。RSpecには、既存の述語メソッド名から?を除いてbe_を前に付けられるようにする仕掛けがあります。be_emptyのようなそれなりに自然な英語としても読めるコードを作れます。include?を基にして次のように書いているコードを見ました。barこのようにもとから動詞であるincludeにbeを付けるのは、英語としてわざわざ間違った形にしているし、DSLの作者の意図にも反しています。be_[arbitrary_predicate](*args)という記述があります。be_を任意の述語(この文脈では述語メソッド)に適用できるということなのですが、決して動詞に適用できるとは書いていません。動詞と述語の区別が明確でない人もいるかも知れないので、これを説明しておきます。「動詞(verb)」は、単語を、形や他の単語と併用される条件に基いて分類した「品詞」の一つです。名詞や、形容詞、副詞などと対比される概念です。3「述部(predicate)」(1単語のときは「述語」)は、文中の単語(の連続)を、意味上の役割に基いて分類した「機能」の一つです。主部や、修飾部などと対比される概念です。method)」は、前の節で述べたように、ある種の限られた返り値を持ち?で終わるメソッドのことです。ここでいう述語は、上記の一般的な意味での述語を狭めたものと見なせます。上の用例では、emptyは形容詞であり述語です。includeは動詞であり述語です。まとめ真理値の周辺については、Rubyは他の多くのプログラミング言語と比較して、仕様の随所で簡潔に使えるようにデザインされています。コードを書くときに、他のプログラミング言語での習慣を引きずってしまって、それを活かし切れていないケースがあるのが残念でした。最後にマネーフォワードでは、エンジニアを募集しています。ご応募お待ちしています。文法によっては、形や制限に加えて意味上の役割も品詞を定義する条件とすることがあります。それでも、品詞と機能が独立した概念であることに違いはありません。ハッシュの生成エンジニアの澤田です。読者になるこのブログについてはてなブログをはじめよう!moneyforwardDevさんは、はてなブログを使っています。ブログを報告する引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。