2012-05-30 56 views
7

可能是一个愚蠢的问题,但我刚刚开始使用F#,并且遇到了一些问题。F# - 乘以float float

说我有这样的功能:

let multiplyByTwo x = x * 2 

当我把这个像这样:

let result = multiplyByTwo 5 

一切正常,结果是10

当我把它叫做像这样:

let result = multiplyByTwo 2.5 

我期望得到5或5.0。但实际结果如下:

let result = multiplyByTwo 2.5 ;;
--------------------------------- ^^^

stdin(4,28):error FS0001:此表达式预计有型

int  

但这里有类型

float 

因为我想这个功能是有些通用的(即同时接受浮点数和整数),我不喜欢这个。我当然的问题是:如何解决这个问题?

+0

我不太了解F#因此评论,但我认为你的函数中的'2'被视为一个int并且期待x也是一个int,是否有某种方法可以投射? – RedEyedMonster

+0

当我开始使用F#时,'float'和'int'的'不兼容性'曾经真的让我感到困扰,但是几年后,我慢慢认识到将它们视为不同类型的有用性。它经常迫使我问自己我真的*想要*。 – Benjol

+0

我认为这是一个语言缺陷,我的解决方法是当我想处理实数并且不关心性能或准确性时,使用浮点数来处理所有事情。 –

回答

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 
+0

我发现这种方法是最干净的方法。看起来是一个很好的解决方案。我只是没有完全理解'inline'关键字(它似乎解析了输入,但我不知道何时何时使用它),但我会在Google上查看。 –

+1

来自MSDN:“没有内联修饰符,类型推断强制函数采取特定类型,在这种情况下为int。但是对于inline修饰符,函数也被推断为具有静态解析的类型参数,这意味着函数接受任何支持浮动转换的类型。“ –

14

当您在F#中编写数字文字(如23.14)时,编译器将其视为特定类型的值,因此使用数字文字的代码不会是多态的。您可以将输入转换为单一类型并使用该类型(例如在desco的答案中使用float)或使用F#的更高级功能...

某些数字操作可以用多态的方式编写,如果您标记代码为inline(这样,编译器可以表示附加的约束并静态地解析它们),如果只使用多态原语(带有附加的静态约束)。

标准运营商polymorpic在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#的文章。

+0

我接受了desco的答案,因为它是最简单的(和imho最干净的)解决方案,但是我非常感谢您的好评!顺便说一句,我在你的网站上读到你是Don Syme的学生之一,很好! –

+0

不错。我认为''答案'将是东西todowih摆脱文字,没有史酷比如何做'虽然。 –

+0

@LeonCullens如果您对“float”结果感到满意,那么@desco的答案是最佳选择。 Don Syme实际上仍然是我的(第二)博士生导师:-)。 –

-1

认为你塞满了这一个。根据2是一个int推断出类型,你可以使用2。0或2f,但所有的结果都是浮动的。

认为你必须深入到他的教程,我也没有,所以我不能帮助那么多。

-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 

这种结构不是类型安全的。另外,报价相对较慢。