3

安全な除算を支援するために、次の演算子を作成しました。

let (/!) a b = 
    if b = 0 then 0 
    else a / b

問題は、整数でのみ機能することです。この関数を任意の数値プリミティブ (int、float、decimal など) で機能させたいと考えています。

私は自動一般化についていくつか読んだことがありますが、完全には浸透していません。また、それが正しい方向に向かっているかどうかもわかりません。

この演算子を一般化するにはどうすればよいですか?

ありがとう、

ジョー

4

1 に答える 1

8

こんにちは、これはちょっとした隠れた逸品ですが、あなたが探しているのはこれです:

let inline (/!) (a : ^a) (b : ^a) : ^a = 
    if b = LanguagePrimitives.GenericZero 
    then LanguagePrimitives.GenericZero 
    else a / b

ところで:これにはこのモンスタータイプがあります:

val inline ( /! ) :
  a: ^a -> b: ^a ->  ^a
    when  ^a : equality and  ^a : (static member get_Zero : ->  ^a) and
          ^a : (static member ( / ) :  ^a *  ^a ->  ^a)

(これが、宣言でこれを書くのが本当に好きではない理由です;))

ご覧のとおり、一般的な数値コードのサポートがありますが、それほど頻繁に議論されるわけではありません (F# には組み込みのような型クラスがいくつかあります。これは例であり、他はcomparableなどです)。

Tomas はこれについて良い記事を書きました:一般的な数値コードを書く

PSどちらも必要ありません^a-しかし、私は署名を書くのが好きです-そして、あなたがこれを行うことができたとしても:

let inline (/!) a b = 
    if b = LanguagePrimitives.GenericZero 
    then LanguagePrimitives.GenericZero 
    else a / b

val inline ( /! ) :
  a: ^a -> b: ^b ->  ^c
    when ( ^a or  ^b) : (static member ( / ) :  ^a *  ^b ->  ^c) and
          ^b : (static member get_Zero : ->  ^b) and  ^b : equality and
          ^c : (static member get_Zero : ->  ^c)

実際の除算演算子は通常、両方の引数に対して 1 つの型にしか対応していないため、役に立ちません。また、私が言ったように、引数名よりも型を強調するのが好きです ;)

楽しい事実

次のように回避できますGenericZero

> let inline (/!) a b = if b = (b-b) then (b-b) else a/b;;

val inline ( /! ) :
  a: ^a -> b: ^b ->  ^b
    when ( ^a or  ^b) : (static member ( / ) :  ^a *  ^b ->  ^b) and
          ^b : (static member ( - ) :  ^b *  ^b ->  ^b) and  ^b : equality

(念のため: ここで特定のタイプ/番号で問題が発生する可能性があります;))

于 2014-08-28T16:44:53.427 に答える