3
// Standard pattern matching.
let Foo x =
  match x with
  | 1 ->
      // ... lots of code, only evaluated if x == 1
  | 2 ->
      // ... lots of code, only evaluated if x == 2

// Standard pattern matching separated out, causing exception.
let Bar x =
  let valueOne = //... lots of code, evaluated always. Exception if value <> 1.
  let valueTwo = //... lots of code, evaluated always. Exception if value <> 2.

  match x with
  | 1 -> valueOne
  | 2 -> valueTwo

「match」を使用したパターン マッチングでは、各パターンのコードが大きくなる可能性があります。上記のFooを参照してください。読みやすさを向上させるために、ブロックを個別の呼び出しとして分割する必要があります。

これに関する問題は、上記のBarのように、パターンが一致していなくても呼び出しが評価される可能性があることです。

  • オプション 1: 遅延評価。
  • オプション 2: 引数/パラメーターを転送します。
  • オプション 3: 引数/パラメーターを転送し、アクティブなパターンを使用します。

各パターンのコードが大きくなる可能性がある場合に、読みやすさを改善するための推奨される方法は何ですか。または、問題に対する他の明白な解決策はありますか?

// ===== OPTION 1 =====
// Pattern matching separated out, lazy eval.
let Foo x =
  let valueOne = lazy //... lots of code, evaluated on Force().
  let valueTwo = lazy //... lots of code, evaluated on Force().

  match x with
  | 1 -> valueOne.Force()
  | 2 -> valueTwo.Force()

// ===== OPTION 2 =====
// Pattern matching separated out, with arguments.
let Foo x =
  let valueOne a = //... lots of code.
  let valueTwo a = //... lots of code.

  match x with
  | 1 -> valueOne x
  | 2 -> valueTwo x

// ===== OPTION 3 =====
// Active Pattern matching separated out, with arguments.
let Foo x = 
  let (|ValueOne|_|) inp =
    if inp = 1 then Some(...) else None

  let (|ValueTwo|_|) inp =
    if inp = 2 then Some(...) else None

  match x with
  | ValueOne a -> a
  | ValueTwo b -> b
4

2 に答える 2

4

一般的に言えば、私は自分のコードのセマンティクスを自分が達成しようとしているもののロジックと一致させようとします。あなたの場合、私はあなたの問題を次のように説明します:

私が受け取る可能性のある単純なデータは 2 つあります。受け取ったものに基づいて、特定のコードを実行します。

これは、オプション 2 に正確にマップされます。コンテキストに応じて、関数をネストする場合とネストしない場合があります。他の 2 つのオプションでは、目標とコードの間に不一致が生じます。

オプション1:

この論理を次のように説明します。

これで、2 つの異なる計算を作成できる情報 (またはコンテキスト) が得られました。そのうちの 1 つは、後で実行する必要があるかもしれません。ここで両方を構築し、後で必要になる方を評価します。

コンテキストや利用可能なデータに変更がないため、これは実際に必要なロジックと一致しません。どちらの方法でも同じコンテキストにいるため、遅延させることで複雑さが増し、関数のロジックが難読化されます。

オプション 3:

この論理を次のように説明します。

2 つのケースのいずれかに該当するデータがあります。どのケースが成立するかを判断するには、複雑なロジックが必要であり、そのロジックは、関数全体の必要な戻り値を決定するために必要なロジックと重複する場合もあります。ケースを判別するロジックを別の関数 (この場合はアクティブ パターン) に移動し、アクティブ パターンの戻り値を使用して関数の結果値を判別します。

これは、制御フロー (次に実行するコードを決定する) と、それぞれの場合に実行されるロジックを融合させます。2 つの間に重複がない場合、次のロジックから制御フローを分離する方がはるかに明確です。

したがって、コードの構造を問題の構造に一致させないでください。そうしないと、追加のコードの複雑さが何を達成するのか疑問に思う人が出てくるでしょう。

于 2017-07-23T13:20:59.653 に答える