有没有更简洁的方法来重写 F# 函数?

Is there a more concise way to rewrite that F# function?

这是一个将数字转换为具有要求的精度和前导符号的字符串的函数:

let formatValueSign (precision: decimal) (value: decimal) =
    let precisionString =
        match precision with
        | 0.1m      -> "{0:+#.0;-#.0; 0.0}"
        | 0.01m     -> "{0:+#.00;-#.00; 0.00}"
        | 0.001m    -> "{0:+#.000;-#.000; 0.000}"
        | 0.0001m   -> "{0:+#.0000;-#.0000; 0.0000}"
        | 0.00001m  -> "{0:+#.00000;-#.00000; 0.00000}"
        | 0.000001m -> "{0:+#.000000;-#.000000; 0.000000}"
        | _         -> "{0:+#0;-#0;0}"

    String.Format(precisionString, value)

预期输出在数字前面有符号,精度用十进制数表示,但也可以作为i传递,其中精度为pown 0.1m i如果方便的话

有没有办法让它更简洁?

如果我理解你想要的是正确的,我认为这样的事情本质上是一样的:

(Decimal.Round(value / precision) * precision).ToString()

而且它还处理精度>1,例如:

formatValueSign 100m -12345.6789m -> "-12300"

如果需要,您可以调整 ToString() 部分以生成前导 + 符号。不过,就我个人而言,我会将其分为两个函数:一个用于生成具有正确精度的小数,另一个用于根据您的喜好格式化它。

最后的想法:我可能会将精度定义为整数指数(例如 -2 而不是 0.01m),因为当前签名接受的精度不是 10 的幂。最好使无效值无法表示恕我直言。

您可以使用 log10 计算格式字符串中零的数量,然后动态生成格式字符串。以下内容无法正确处理极端情况,但适用于范围中间的情况:

let formatValueSign (precision: decimal) (value: decimal) =
  let places = int (log10 (float (1.0m/precision)))
  let zeros = String.replicate places "0"
  let precisionString = sprintf "{0:+#.%s;-#.%s; 0.%s}" zeros zeros zeros
  String.Format(precisionString, value)