9

アクティブ パターンを使用して再帰降下パーサーを作成することで F# を学習しています。

すべてのルールまたは部分的なアクティブ パターンをさまざまな方法で組み合わせる必要があるため、アクティブ パターンをパラメーターとして渡す構文に本当に不満を感じています。

次の例は、私が抱えている問題を示しています。

// Combines two patterns by chaining them.
let (|Chain|_|) (|Pattern1|_|) (* Should I use pipes here? *) (|Pattern2|_|) data =
    match data with
    |Pattern1 result ->
        match result with
        |Pattern2 result2 -> Some result2
        |_ -> None
    |_ -> None 

// Stupid test patterns
let (|IfBiggerThan10ThenDouble|_|) value = if value > 10 then Some (value*2) else None
let (|IfLessThan100ThenDouble|_ |) value = if value < 100 then Some (value*2) else None

match 20 with
// Do I need pipes here?
|Chain (IfBiggerThan10ThenDouble IfLessThan100ThenDouble) value -> printfn "%A" value // Should print 80
| _ -> printfn "Did not match"

私の主な混乱は、「|」についてのようです オペレーター。柄の種類の一部と思われることもあれば、名前の一部と思われることもあります。

4

1 に答える 1

14

必要な結果が得られるパターンを直接ネストできるため、パターンの独自の連鎖を実際に実装する必要はありません。

match 20 with
| IfBiggerThan10ThenDouble(IfLessThan100ThenDouble value) -> printfn "%A" value
| _ -> printfn "Did not match"

IfBiggerThan10ThenDoubleこれは最初に値を計算20*2してネストされたパターンに渡すパターンを呼び出しますIfLessThan100ThenDouble。これは再び値を 2 倍にし、それをvalueシンボルにバインドします (成功した場合)。

そうは言っても、パターンの実装はChain実際に機能し、次のように呼び出すことができます。

match 20 with
| Chain (|IfBiggerThan10ThenDouble|_|) (|IfLessThan100ThenDouble|_|) value -> 
    printfn "%A" value // Should print 80
| _ -> printfn "Did not match"

一般に、アクティブ パターン(|P|_|)は、実際には特別な名前を持つ単なる関数です。通常の関数として扱い、記述して呼び出す(|P|_|) argumentか、値として扱い、他の関数またはパラメーター化されたアクティブ パターンに引数として渡すことができます。Chain通常の関数を使用するパターンとして実装した場合、コードは機能します。

let (|Chain|_|) f g data =
    f data |> Option.bind (fun r -> g data)

次にChain <arg1> <arg2> <pat>、引数として 2 つの関数を使用してパラメーター化されたアクティブ パターンを呼び出すだけです。呼び出されると、結果を pattern にバインドします<pat>。上記の例では、2 つの引数はパターンを表す関数値です (これらは通常の関数である可能性がありますが、構文上の制限によりラムダ関数ではない可能性があります)。

于 2014-03-25T13:24:18.340 に答える