8

ばかげた質問かもしれませんが、F# を使い始めたばかりで、少し問題があります。

次のような関数があるとします。

let multiplyByTwo x = x * 2

これを次のように呼び出すと:

let result = multiplyByTwo 5

大丈夫です、結果は10です。

このように呼び出すと:

let result = multiplyByTwo 2.5

結果として 5 または 5.0 が得られると予想しています。ただし、実際の結果は次のとおりです。

結果をさせてください=multiplyByTwo 2.5;;
----------------------------------^^

stdin(4,28): エラー FS0001: この式には型があると予想されていました

int     

しかし、ここにはタイプがあります

float

私はこの関数をある程度一般的なもの (つまり、浮動小数点数と整数の両方を受け入れる) にしたいので、これは好きではありません。もちろん私の質問:これをどのように解決しますか?

4

3 に答える 3

14

F# で数値リテラル (2または など3.14) を記述すると、コンパイラはそれを特定の型の値として扱うため、数値リテラルを使用するコードは多態的ではありません。入力を単一の型に変換してその型で作業するか ( floatdesco の回答のように)、F# のより高度な機能を使用することができます...

コードを次のようにマークする場合inline(この方法では、コンパイラは追加の制約を表し、それらを静的に解決できます)、および多態プリミティブのみを使用する場合 (追加の静的制約を使用) は、特定の数値演算を多態的に記述することができます。

標準演算子はinline関数で多相的であり、F# ライブラリは 1 と 0 (2 ではない) を表す多相値を取得する方法を提供しますが、必要な関数を記述するにはそれで十分です。

let inline twoTimes n = 
  let one = LanguagePrimitives.GenericOne
  n * (one + one)

twoTimes 2
twoTimes 2.0

これをより良くしたい場合は、数値リテラルを定義して (以前の StackOverflow の質問に対する Daniel の回答を参照)、実際に次のように書くことができます。

let inline twoTimes n = n * 2G

特別な数値リテラル2Gは、上記で使用した手法を使用して、指定された数のジェネリック 1 値を合計する関数の呼び出しに変換さNumericLiteralGれます (したがって、大きな数に対しては効率的ではありません!) 詳細については、私の最近の記事も参照してください。F# での一般的な数値コードの記述について。

于 2012-05-30T22:06:14.250 に答える
12
let inline mulBy2 x = (float x) * 2.0

let a = mulBy2 3 // 6.0 : float
let b = mulBy2 2.5 // 5.0 : float
let c = mulBy2 "4" // 8.0 : float
于 2012-05-30T22:07:21.067 に答える
-1

「ちょっとしたハック」を使うのが怖くないなら、これは役に立つかもしれません:

// Copied from Core.LanguagePrimitives.IntrinsicFunctions.retype
[<NoDynamicInvocation>]
let inline retype (x:'a) : 'b = (# "" x : 'b #)

let inline multiplyByTwo (x:'a) = x * (retype 2:'a)

// use
let result1 = multiplyByTwo 5 // 10
let result2 = multiplyByTwo 2.5 // 5.0

型チェックは実行時に行われるため、この構造は型安全ではありません。また、見積もりは比較的遅いです。

于 2012-05-30T22:35:06.067 に答える