10

if/elseMLファミリーの言語では、人々は構築するためにパターンマッチングを好む傾向があります。F#では、パターンマッチング内でガードを使用するif/elseと、多くの場合、簡単に置き換えることができます。

たとえば、単純なdelete1関数は、以下を使用せずに書き直すことができますif/else(を参照delete2)。

let rec delete1 (a, xs) =
    match xs with
    | [] -> []
    | x::xs' -> if x = a then xs' else x::delete1(a, xs') 

let rec delete2 (a, xs) =
    match xs with
    | [] -> []
    | x::xs' when x = a -> xs'
    | x::xs' -> x::delete2(a, xs') 

別の例は、二次関数を解くことです。

type Solution =
    | NoRoot
    | OneRoot of float
    | TwoRoots of float * float

let solve1 (a,b,c) = 
    let delta = b*b-4.0*a*c
    if delta < 0.0 || a = 0.0 then NoRoot 
    elif delta = 0.0 then OneRoot (-b/(2.0*a))
    else 
        TwoRoots ((-b + sqrt(delta))/(2.0*a), (-b - sqrt(delta))/(2.0*a))

let solve2 (a,b,c) = 
    match a, b*b-4.0*a*c with
    | 0.0, _  -> NoRoot
    | _, delta when delta < 0.0 -> NoRoot
    | _, 0.0 -> OneRoot (-b/(2.0*a))
    | _, delta -> TwoRoots((-b + sqrt(delta))/(2.0*a),(-b - sqrt(delta))/(2.0*a))

if/else醜い構成を無視するために、ガードとのパターンマッチングを使用する必要がありますか?

ガードでパターンマッチングを使用することに対するパフォーマンスへの影響はありますか?実行時にパターンマッチングがチェックされているので遅いようです。

4

4 に答える 4

10

どちらにも独自の場所があります。人々は、値をチェックするためのIf / else構文に慣れていますが、パターンマッチングはステロイドのIf/elseのようなものです。パターンマッチングを使用するとdecomposed、データの構造と比較したり、ガードを使用して、分解されたデータの一部やその他の値に追加の条件を指定したりできます(特に、再帰的なデータ構造やF#のいわゆる識別された共用体の場合)。 。

私は個人的にif/elseを単純な値の比較(true / false、intなど)に使用することを好みますが、再帰的なデータ構造など、分解された値と比較する必要がある場合は、パターンマッチングに勝るものはありません。

最初にそれを機能させ、エレガントでシンプルにします。次に、パフォーマンスの問題が発生した場合は、パフォーマンスの問題を確認します(これは主に、パターンマッチングではなく、他のロジックが原因です)。

于 2011-11-03T05:47:12.637 に答える
10

正しい答えはおそらくそれによって異なりますが、ほとんどの場合、コンパイルされた表現は同じであると思います。例として

let f b =
  match b with
  | true -> 1
  | false -> 0

let f b =
  if b then 1
  else 0

両方とも

public static int f(bool b)
{
    if (!b)
    {
        return 0;
    }
    return 1;
}

それを考えると、それは主にスタイルの問題です。個人的には、ケースが常に整列されて読みやすくなるため、パターンマッチングが好きです。また、(おそらく)後で拡張してより多くのケースを処理する方が簡単です。if//の進化にパターンマッチングを考えthenますelse

ガードの有無にかかわらず、パターンマッチングの追加の実行時コストもありません。

于 2011-11-02T20:18:08.700 に答える
1

パターンマッチングは通常より柔軟であるという@Danielに同意します。この実装を確認してください。

type Solution = | Identity | Roots of float list

let quadraticEquation x =

    let rec removeZeros list =
        match list with
        | 0.0::rest -> removeZeros rest
        | _ -> list
    let x = removeZeros x

    match x with
    | [] -> Identity // zero constant
    | [_] -> Roots [] // non-zero constant
    | [a;b] -> Roots [ -b/a ] // linear equation
    | [a;b;c] ->
        let delta = b*b - 4.0*a*c
        match delta with
        | delta when delta < 0.0 -> 
            Roots [] // no real roots
        | _ ->
            let d = sqrt delta
            let x1 = (-b-d) / (2.0*a)
            let x2 = (-b+d) / (2.0*a)
            Roots [x1; x2]
    | _ -> failwithf "equation is bigger than quadratic: %A" x

また、https://fsharpforfunandprofit.com/learning-fsharp/で、if-elseの使用は推奨されていないことに注意してください。機能性の低い入札と見なされます。

于 2018-04-09T10:36:19.733 に答える
0

私は自作の素数ジェネレーターでいくつかのテストを行いました。「ifthenelse」があると言えば、パターンマッチングよりも大幅に遅いのですが、理由は説明できませんが、命令型をテストした限りではF#の一部は、最適なアルゴリズムに関しては、再帰的な機能スタイルよりも実行時間が遅くなります。

于 2017-03-04T11:36:08.510 に答える