F# Ununit - 在函数内重新组合

发布于 2024-08-04 02:03:54 字数 1048 浏览 6 评论 0原文

这个问题与这些问题密切相关(123)

我正在使用一个尚未处理单位的外部库的衡量标准。我希望能够在传递值之前“ununit”它们,然后在返回结果时“reunit”它们。

问题是我想避免被迫提前声明哪些单位。

示例片段

let ExternalNonUnitAwareFunction s = s + 1.

let MyUnitAwareClient (s:float<'u>) =  //'
    //1. this option "flattens" to no unit, or fixes to first inferred unit
    //let (unit:float<'u>) = 1.0<_>  
    //2. this works fine, except for 0!
    let unit = s / (float s) 
    s |> float |> ExternalNonUnitAwareFunction |> (*) unit

我还没有弄清楚如何处理这个问题...

更新 如果我理解正确, F# 的最终版本将包含执行此操作的函数。

This question is closely related to these ones (1, 2, 3)

I'm using an external library which doens't (yet) handle units of measure. I want to be able to 'ununit' values before I pass them in, then 'reunit' them when I get the results back.

The catch is that I'd like to avoid being forced to declare WHICH units in advance.

Example snippet

let ExternalNonUnitAwareFunction s = s + 1.

let MyUnitAwareClient (s:float<'u>) =  //'
    //1. this option "flattens" to no unit, or fixes to first inferred unit
    //let (unit:float<'u>) = 1.0<_>  
    //2. this works fine, except for 0!
    let unit = s / (float s) 
    s |> float |> ExternalNonUnitAwareFunction |> (*) unit

I haven't managed to work out how to handle this one...

Update
If I have understood correctly, the final version of F# will include functions to do this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

纵情客 2024-08-11 02:03:55

目前,拳击和选角似乎有效:

let MyUnitAwareClient (s:float<'u>) =  
  let result = s |> float |> ExternalNonUnitAwareFunction
  (box result :?> float<'u>)

不过,如果度量单位在发布之前经历一些进一步的变化,我不会感到惊讶,这可能会打破这一点。您还可以制作更通用的版本,例如:

let reunit (f:float -> float) (v:float<'u>) =
  let unit = box 1. :?> float<'u>
  unit * (f (v/unit))

编辑

现在有一个 FloatWithMeasure 函数可以“转换为单位”:

http://msdn.microsoft.com/en-us/library/ee806527(VS.100).aspx

For now, boxing and casting appears to work:

let MyUnitAwareClient (s:float<'u>) =  
  let result = s |> float |> ExternalNonUnitAwareFunction
  (box result :?> float<'u>)

I wouldn't be surprised if the units of measure stuff goes through some further changes before release, though, which might break this. You can also make a more generic version, such as:

let reunit (f:float -> float) (v:float<'u>) =
  let unit = box 1. :?> float<'u>
  unit * (f (v/unit))

EDIT

There is now a FloatWithMeasure function to 'cast to units':

http://msdn.microsoft.com/en-us/library/ee806527(VS.100).aspx

ι不睡觉的鱼゛ 2024-08-11 02:03:55

只是为了好玩,这里是相反的:

let deunit (fn:float<'u> -> float<'v>) (v:float) =
    let unit = box 1. :?> float<'u>
    fn(v * unit) |> float

测试:

#light

[<Measure>]type mm

let reunit (fn:float -> float) (v:float<'u>) =
    let unit = box 1. :?> float<'u>
    unit * (fn(v/unit))

let deunit (fn:float<'u> -> float<'v>) (v:float) =
    let unit = box 1. :?> float<'u>
    fn(v * unit) |> float

let nounits v = v + 2.5            //function with no units
let withunits = reunit nounits     //make it handle units (run with next line)
withunits 2.5<mm>                  //try it -> 5.0<mm>

let newnounits = deunit withunits  //remove unit handling
newnounits 2.5                     //try it -> 5.0<mm>

let withunits2 = reunit newnounits //reunit to another function
withunits2 2.5<mm^2>               //try with different units

如果你自己运行 let withunits = reunit nounits ,那么 #"(£$! 会出现奇怪的东西。所以你必须使用 withunits 的行运行它,我想这并不奇怪,您必须传递 (v:float<'u>) 来重新组合 F# 才能计算出 'u我猜可能会使重聚的兴趣有限...

更新:一个稍微古怪的解决方法是传递“模型”值。

let reunit2 (fn:float -> float) (model:float<'u>*float<'v>) =
    let unitin = box 1. :?> float<'u>
    let unitout = box 1. :?> float <'v>
    (fun v -> (fn(v / unitin)) * unitout)

let withunits3 = reunit2 nounits (0.<mm>, 0.<mm^2>)
withunits3 3.5<mm>

And just for fun, here is the opposite:

let deunit (fn:float<'u> -> float<'v>) (v:float) =
    let unit = box 1. :?> float<'u>
    fn(v * unit) |> float

Test :

#light

[<Measure>]type mm

let reunit (fn:float -> float) (v:float<'u>) =
    let unit = box 1. :?> float<'u>
    unit * (fn(v/unit))

let deunit (fn:float<'u> -> float<'v>) (v:float) =
    let unit = box 1. :?> float<'u>
    fn(v * unit) |> float

let nounits v = v + 2.5            //function with no units
let withunits = reunit nounits     //make it handle units (run with next line)
withunits 2.5<mm>                  //try it -> 5.0<mm>

let newnounits = deunit withunits  //remove unit handling
newnounits 2.5                     //try it -> 5.0<mm>

let withunits2 = reunit newnounits //reunit to another function
withunits2 2.5<mm^2>               //try with different units

Weird stuff with that #"(£$! Value restriction error in there if you run let withunits = reunit nounits on it's own. So you have to run it with the line that uses withunits. I guess it's not surprising, you have to pass in the (v:float<'u>) to reunit for F# to be able to work out what 'u is. Possibly makes reunit of limited interest, I guess...

UPDATE: A slightly kooky workaround is to pass in 'model' values

let reunit2 (fn:float -> float) (model:float<'u>*float<'v>) =
    let unitin = box 1. :?> float<'u>
    let unitout = box 1. :?> float <'v>
    (fun v -> (fn(v / unitin)) * unitout)

let withunits3 = reunit2 nounits (0.<mm>, 0.<mm^2>)
withunits3 3.5<mm>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文