3

一見些細な問題で立ち往生しています。ポイントフリーの方法で記述されている場合、関数で例外を処理できません。

次の2つの機能を検討してください。

let divide1 x y =
    try
        x / y
    with
        | :? System.DivideByZeroException -> 42

let divide2 =
    try
        (/)
    with
        | :? System.DivideByZeroException -> fun _ _ -> 42

let x1 = divide1 5 0 // works fine
let x2 = divide2 5 0 // doesn't handle an exception

どちらの関数も一見同じように見えますが、タイプが異なります。

val divide1: int -> int -> int
val divide2: (int -> int -> int)

明らかに、divide2例外を処理しようとさえしません。単に演算子を返します。

divide2例外を適切な方法で処理するために何ができますか(特にその引数を宣言することを除く)?

4

2 に答える 2

7

これが、ポイントフリースタイルに問題があると思う理由の1つです。(または標準ループやその他のF#機能)のような標準言語構造を使用することは困難でtry .. withあり、それらをカスタムコンビネータに置き換える必要があります。この場合、tryWith2例外ハンドラーで2つの引数関数をラップするコンビネーターを定義できます。

let tryWith2 f h a b = 
  try f a b // Call the function with two arguments
  with e -> 
    // Try running the error handler with the exception
    match h e with 
    | Some g -> g a b // Error handler provided another function
    | _ -> reraise()  // Error was not handled - reraise

次に、このようなポイントフリースタイルで関数を記述できます(エラー処理はまだポイントフリーではありませんが、これをあまりにもばかげたものにしたくありません:-))

let divide2 =
  tryWith2 (/) (function
      | :? System.DivideByZeroException -> Some(fun _ _ -> 42)
      | _ -> None)

let x1 = divide2 5 0 // returns 42
let x2 = divide2 5 1 // returns 5

もちろん、F#でもポイントフリースタイルは便利です。たとえば、DSLを作成する場合、宣言型仕様を作成するのに最適な方法です(プリミティブは、より高いレベルの抽象化を使用して何かを表現するため)。ここでは、通常のF#コードに非常に近いものを表現する必要があります。これは、通常のF#コードとして最もよく表現されると思います。

于 2012-12-16T01:08:42.770 に答える
4

覚えておく必要があるのは、divide2では、XをYで割った結果を返すのではなく、XをYで割る関数を返すということです。letバインディングのコードは、指定されていないため、すぐに実行されます。関数の構文。より長い関数構文を持つ両方の分割バインディングを見てみましょう。

let divide1 =
    fun x ->
        fun y ->
            try
                x / y
            with
                | :? System.DivideByZeroException -> 42

let divide2 =
    try
        fun x ->
            fun y ->
                x / y
    with
        | :? System.DivideByZeroException -> fun _ _ -> 42

このように表示すると、2つの定義がどのように異なるかが明確になります。ブロックはtry完全に異なる場所にあり、異なる時点で実行されます。

例外処理などのロジックを既存の関数に追加する唯一の方法は、で行うようにdivide1、またはTomasが示したように高階関数でラップすることです。

于 2012-12-16T23:47:43.437 に答える