【问题标题】:Are there tricks for doing implicit conversions in F#?在 F# 中进行隐式转换有技巧吗?
【发布时间】:2010-11-03 00:04:50
【问题描述】:

考虑用这个 F# 代码来对下面的 i 3 和 5 的倍数求和:

let isMultipleOfThreeOrFive n = 
    (n % 3 = 0) || (n % 5 = 0)

let sequenceOfMultiples i =
    seq {1 .. i - 1} |> Seq.filter isMultipleOfThreeOrFive

由于iint,如果i 很大,则会溢出。这个带有BigInteger 的版本可以解决这个问题:

let isMultipleOfThreeOrFive n = 
    (n % 3I = 0I) || (n % 5I = 0I)

let sequenceOfMultiples (i : System.Numerics.BigInteger) =
    seq {1I .. i - 1I} |> Seq.filter isMultipleOfThreeOrFive

要将int 版本转换为BigInteger 版本,我必须在数字后添加大量Is。这是因为 F# 不进行隐式转换。

有没有简单的方法来解决这个问题,或者在 6 个地方添加Is 是最好的做法?

【问题讨论】:

  • 这不是一个错误,而是一个特性 ;-)

标签: f#


【解决方案1】:

这并不能完全回答您的问题,但请注意,也可以通过定义您自己的数字文字使 sequenceOfMultiples 通用:

module NumericLiteralG =
  let inline FromZero() = LanguagePrimitives.GenericZero
  let inline FromOne() = LanguagePrimitives.GenericOne
  let inline FromInt32 (i:int) =
    let zero : ^a = FromZero()
    let one : ^a = FromOne()
    let rec compute : int -> ^a = function
    | 0 -> zero
    | n -> 
        let half = compute (n/2)
        let whole = half + half
        if (n%2 = 0) then whole
        else whole + one
    compute i

let inline isMultipleOfThreeOrFive n = 
    (n % 3G = 0G) || (n % 5G = 0G)

let inline sequenceOfMultiples i =
    seq {1G .. i - 1G} |> Seq.filter isMultipleOfThreeOrFive

let bigintSeq = sequenceOfMultiples 100I
let intSeq = sequenceOfMultiples 100

// doesn't compile
let stringSeq = sequenceOfMultiples "100"

【讨论】:

    【解决方案2】:

    你做了最好的事情。

    (没有比添加您添加的六个字符更容易“绕过”它的方法了。即使没有隐式转换,F# 也比 C# 短,并且增量从 int 到 BigInteger在 F# 中也比 C# 小。所以不要为隐式转换的丢失感到难过 - 为所有其他简洁性获胜感到高兴。:))

    【讨论】:

    • 然而速度损失很大。
    • 嗯? F# BigInteger 和 C# BigInteger 代码做同样的工作?
    • 谢谢,布赖恩。在这里和 reddit 上阅读你的东西总是很愉快。
    • 虽然我认为静态地“通用”会成功,因为 F# 可以在编译时将代码专门化为手头的特定类型
    猜你喜欢
    • 1970-01-01
    • 2017-05-19
    • 2018-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 2013-05-03
    • 1970-01-01
    相关资源
    最近更新 更多