2016-08-16 3 views
4

今、私は奇妙に動作しているネストされたパターンマッチを持っています。ここでこのF#ネストマッチ式が正しく機能しないのはなぜですか?

は、コードスニペット残念ながら

match setting with 
| "-f" | "--file" ->   // Open file 
    ({ state with file = Some (cur_dir + "\\" + elem) }, "") 
| "" ->       // Option without parameter 
    match elem with 
    | "-h" | "--help" ->  // Display help message 
     ({ state with help = true }, "") 
    | "-r" | "--readonly" -> // Open with readonly 
     ({ state with readonly = true }, "") 
    | opt -> (state, opt) 
| _ -> (state, "")    // Ignore invalid option 

である私は上記のコードをコンパイルするとき、私は2つの警告を取得します。最後のワイルドカードパターンに到達できないことが示されます。もう1つは、最初の一致ステートメントが不完全であることを示します。

この2つの警告は互いに矛盾しているようですが、式をより明確にするためにかっこを追加すると、警告が消え、コードが正しく機能します。

match setting with 
| "-f" | "--file" ->   // Open file 
    ({ state with file = Some (cur_dir + "\\" + elem) }, "") 
| "" ->       // Option without parameter 
    (match elem with 
     | "-h" | "--help" ->  // Display help message 
      ({ state with help = true }, "") 
     | "-r" | "--readonly" -> // Open with readonly 
      ({ state with readonly = true }, "") 
     | opt -> (state, opt)) 
| _ -> (state, "")    // Ignore invalid option 

私の質問は次のとおりです。元のコードで何が間違っていましたか?誤った括弧の場合ではなく、コンパイラがそれぞれのマッチが終わるところが明白であるように思えます。

編集:ここでは、完全な機能があります、ケースにはそれが

let process_args argv = 
    let (result, _) = ((default_settings, "-f"), argv) ||> 
     Array.fold (fun (state, setting) elem -> 
      match setting with 
      | "-f" | "--file" ->   // Open file 
       ({ state with file = Some (cur_dir + "\\" + elem) }, "") 
      | "" ->       // Option without parameter 
       match elem with 
       | "-h" | "--help" ->  // Display help message 
        ({ state with help = true }, "") 
       | "-r" | "--readonly" -> // Open with readonly 
        ({ state with readonly = true }, "") 
       | opt -> (state, opt) 
      | _ -> (state, "")    // Ignore invalid option 
     ) in 
    result 

を助け、私はまた、このエラーは、光と詳細な構文の両方で発生することに注意してください。

Edit2:わずかに変更された関数を誤って貼り付けたため、警告だけでなくコンパイルエラーが発生しました。謝罪いたします。

let process_args argv = 
    let (result, _) = ((default_settings, "-f"), argv) 
     ||> Array.fold (fun (state, setting) elem -> 
     // (snip rest of function) 

2つのエラーがlet (result, _) = ...letにあり、||>オペレータに:私はVSコードにあなたの完全な機能をコピーすると

+0

あなたの例は私にとってうまくいきます。ほぼ間違いなくインデントエラーです。 – Ringil

+0

この例題は、ソースコードからそのままコピー&ペーストされています。また、「#ライト」をオフにしたかどうかにかかわらず、エラーが発生します。 – idlys

+0

マッチステートメントをVSコードにコピーすると、Ionideプラグインに警告が表示されません。しかし、あなたの完全な 'process_args'関数をコピーすると、' let'ステートメントでインデントエラーが発生します。私は完全な答えを書くつもりですが、短いバージョン(あなたが待つ必要はありません)は次のとおりです: '((default_settingsなどのタプルを次の行に移動して4つのスペースをインデントし、変更して、あなたのコードがうまくいくはずです – rmunn

答えて

4

は、私は2つのエラー、同じインデントミスによるの両方を取得します。 letのエラーは、

不完全な値または関数の定義です。これが式の中にある場合、式の本体は 'let'キーワードと同じ列に字下げする必要があります。

||>にエラーがある:結合で

予期中置演算子。この点または他のトークンの前またはそれ以前に、不完全な構造化された構成が必要です。これらのエラーの

どちらも実際の原因は||>オペレータの使用でシンプルなインデントの間違いですので、あなたは何が悪かったのかを把握するうえで、実際にかなり役に立たないです。

F# code formatting guidelinesによると、「パイプ」演算子(|>||>など)は、操作対象の式と同じレベルでインデントする必要があります。あなたのコードでは、||>演算子は(result, _)タプルの下に字下げされています。しかし、そのタプルは実際には||>が何を操作しようとしているのではありません。そのタプルはターゲットです。 ||>が動作しているという表現は、((default_settings, "-f"), argv)タプルです。ですから、このようなコードをインデントしておく必要があります

let process_args argv = 
    let (result, _) = ((default_settings, "-f"), argv) 
         ||> Array.fold (fun (state, setting) elem -> 
         // (snip rest of function) 

さも:

let process_args argv = 
    let (result, _) = 
     ((default_settings, "-f"), argv) 
     ||> Array.fold (fun (state, setting) elem -> 
     // (snip rest of function) 

秒1はIMHO、より良いです。

+0

回答ありがとうございました。また、ライト構文がオンで、 '||>'演算子がletバインディングと同じ行にある場合、マッチ警告を出します。そのような困惑の警告です... – idlys

+0

私は混乱して元の投稿に間違ったコードをコピーしたことに言及する必要があります。私は私のコードでletバインディングと同じ行に '||>それを実行し、警告を得た。私はそれをなぜ変更したのか分からない。私はそれを修正します。間違って申し訳ありません! – idlys

+2

あなたはtr F#を冗長な構文(つまり、 '#light"をつけて '')で記述すると、構文の詳細をよく知っている人はほとんどいないでしょう。軽い構文は、F#コードのデフォルトおよびデファクトスタンダードになりました。別のML言語からコードをコピーして貼り付け、最小限の変更で動作させたい場合を除き、F#の軽い構文を学ぶことをおすすめします**。 – rmunn

関連する問題