可能是一个愚蠢的问题,但我刚开始使用F#而且我遇到了一些问题。
说我有这样的功能:
let multiplyByTwo x = x * 2
当我这样称呼时:
let result = multiplyByTwo 5
一切都很好,结果是10。
当我这样称呼时:
let result = multiplyByTwo 2.5
我希望得到5或5.0。但实际结果如下:
让result = multiplyByTwo 2.5 ;;
--------------------------------- ^^^stdin(4,28):错误FS0001:此表达式应具有类型
int
但这里有类型
float
因为我希望这个函数有些通用(即接受浮点数和整数),我不喜欢这个。我的问题当然是:如何解决这个问题?
答案 0 :(得分:14)
当您在F#中编写数字文字(例如2
或3.14
)时,编译器会将其视为特定类型的值,因此使用数字文字的代码不会是多态的。您可以将输入转换为单一类型并使用该类型(如desco的答案中的float
)或使用F#的更多高级功能...
如果您将代码标记为inline
(这样,编译器可以表示其他约束并静态解析它们),并且您只使用多态基元(带附加值),则可以以多态方式编写某些数值运算静态约束)。
标准运算符在inline
函数中是多态的,而F#库提供了一种获取表示1和0(但不是2)的多态值的方法,但这足以编写你想要的函数:
let inline twoTimes n =
let one = LanguagePrimitives.GenericOne
n * (one + one)
twoTimes 2
twoTimes 2.0
如果你想使这个更好,你可以定义一个数字文字(见Daniel's answer to earlier StackOverflow question),然后你可以实际写:
let inline twoTimes n = n * 2G
特殊数字文字2G
被转换为对NumericLiteralG
函数的调用,该函数使用我上面使用的技术对指定数量的通用1值求和(因此对大型函数来说效率不高)数字!)有关详情,请参阅我最近关于writing generic numeric code in F#的文章。
答案 1 :(得分: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
答案 2 :(得分:-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
此构造不是类型安全的,因为类型检查是在运行时完成的。此外,报价相对较慢。