8

可能是一个愚蠢的问题,但我刚开始使用 F#,我遇到了一个小问题。

假设我有这样的功能:

let multiplyByTwo x = x * 2

当我这样称呼它时:

let result = multiplyByTwo 5

一切正常,结果是 10。

当我这样称呼它时:

let result = multiplyByTwo 2.5

我希望得到 5 或 5.0 作为结果。然而实际结果是这样的:

让结果 = multiplyByTwo 2.5;;
---------------------------------^^^

标准输入(4,28):错误 FS0001:此表达式应具有类型

int     

但这里有类型

float

因为我希望这个函数有点通用(即接受浮点数和整数),所以我不喜欢这个。我的问题当然是:如何解决这个问题?

4

3 回答 3

14

当您在 F# 中编写数字文字(例如2or 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

如果您想让它变得更好,您可以定义一个数字文字(请参阅Daniel 对早期 StackOverflow 问题的回答),然后您实际上可以只写:

let inline twoTimes n = n * 2G

特殊的数字文字2G被转换为对一个函数的调用,该函数NumericLiteralG使用我上面使用的技术对指定数量的通用 1 值求和(因此它对大数字无效!)有关更多信息,您还可以查看我最近的文章在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 回答