2
type Alignment =
     | Horizontal
     | Vertical

let getMainAttr = function
                  | Horizontal -> fst
                  | Vertical -> snd

let check alignment =
    let mainAttr = getMainAttr alignment
    mainAttr (2,3) |> ignore
    mainAttr (2.0, 3.0) // error

val getMainAttr : _arg1:Alignment -> ('a * 'a -> 'a)
mainAttr : (int * int -> int) // because of the value restriction

ジェネリックにする唯一の方法は、明示的にすることです。let mainAttr x = getMainAttr alignment x

ただし、クロージャーを使用しなくなったため、mainAttr呼び出されるたびalignmentにチェックする必要があります。

alignmentジェネリックであるだけでなく、一度だけチェックする方法はありますか?

4

2 に答える 2

2

@Daniel が説明しているように、(値が関数であっても) F# 計算の結果である汎用値の作成を禁止する値制限の制限に達しています。これについての詳細は、他の SO の質問で見つけることができます。高度なポイントに関する記事もあります。この制限の理由は、ジェネリック値がタイプ セーフに抜け穴をもたらす可能性があるためです。

あなたの例では、getMainAttr関数を繰り返し実行してもそれほどオーバーヘッドが追加されないため、実際に心配する必要はありません。関数がより複雑な計算を行う場合は、(単純な関数ではなく) ジェネリック メソッドを使用してインターフェイスを返すことができます。

/// Interface with as single generic function that selects element of a pair
type PairSelector = 
  abstract Invoke<'T> : 'T * 'T -> 'T

// Two possible implementations of the interface 
let first = { new PairSelector with member x.Invoke(a, b) = a }
let second = { new PairSelector with member x.Invoke(a, b) = b }

// Return a non-generic `PairSelector` value instead of a generic function
let getMainAttr = function
                  | Horizontal -> first
                  | Vertical -> second

// Now we can get `PairSelector` value and call it with different type arguments    
let check alignment =
    let mainAttr = getMainAttr alignment
    mainAttr.Invoke (2,3) |> ignore
    mainAttr.Invoke (2.0, 3.0) 
于 2012-11-16T16:01:45.417 に答える
1

そのままmainAttr関数です。値を汎用にすることはできません。あなたが発見したように、解決策は、パラメーターを明示的にすることで「真の」関数にすることです。

最後の質問ですalignmentが、これは関数ではなく値であることを考えると、何回評価されるか本当に気にしますか? よくわかりませんが、カリー化がこれに影響するとは思いません。

于 2012-11-16T15:50:57.220 に答える