use*_*923 12 f# units-of-measurement f#-3.0
我希望能够这样做:
let duration = 1<hours> + 2<minutes> + 3<seconds>
Run Code Online (Sandbox Code Playgroud)
具有以下类型和功能(可能还有更多计量单位):
type [<Measure>] seconds
type [<Measure>] minutes
type [<Measure>] hours
let seconds_per_minute = 60<seconds> / 1<minutes>
let minutes_per_hour = 60<minutes> / 1<hours>
let minutes_to_seconds minutes seconds = minutes * seconds_per_minute + seconds
let hours_to_minutes hours minutes = hours * minutes_per_hour + minutes
Run Code Online (Sandbox Code Playgroud)
因此,基本上应该使用"hours_to_minutes"来添加小时和分钟,并且当我在上面键入时,应该使用"minutes_to_seconds"来添加分钟和秒.
这可能在F#中做到吗?
Gus*_*Gus 15
实际上有可能,有一种方法可以做到这一点:
type [<Measure>] seconds
type [<Measure>] minutes
type [<Measure>] hours
let seconds_per_minute = 60<seconds> / 1<minutes>
let minutes_per_hour = 60<minutes> / 1<hours>
let minutes_to_seconds minutes seconds = minutes * seconds_per_minute + seconds
let hours_to_minutes hours minutes = hours * minutes_per_hour + minutes
type D1 = D1
type D2 = D2
type Sum = Sum with
static member inline ($) (Sum, _:^t when ^t: null and ^t: struct) = id
static member inline ($) (Sum, b) = fun _ _ a -> a + b
static member ($) (Sum, b:int<minutes>) = fun D1 _ a -> hours_to_minutes a b
static member ($) (Sum, b:int<seconds>) = fun D1 D2 a -> minutes_to_seconds a b
let inline (+) a b :'t = (Sum $ b) D1 D2 a
let duration = 1<hours> + 2<minutes> + 3<seconds>
Run Code Online (Sandbox Code Playgroud)
但它真的很hacky,我不推荐它.
UPDATE
根据评论,这里有一些答案:
此技术使用在编译时解析的重载,因此在运行时不会降低性能.它基于我前一段时间在博客中写的内容.
要添加更多重载,您必须添加更多伪参数(D3,D4...),最终如果您决定添加一些与现有重载冲突的重载,您可能必须使用三元运算符(?<-)或带有显式静态成员的函数调用限制.这是一个示例代码.
我想我不会使用它,因为它需要很多hacks(Dummy重载和2个虚拟类型)并且代码变得不那么可读.最终,如果F#基于重载增加了对内联函数的更多支持,我肯定会考虑它.
Phil Trelford的技术(在Reed的答案中提到)在运行时工作,第三种选择是使用幻像类型,它可能需要更少的黑客攻击.
结论
如果我把所有的替代品之间选择,我会用这种方法,但是是在调用点,我的意思是我会这样定义转换功能更加明确minutes,seconds而且这种方式在调用点我会写:
let duration = seconds 1<hours> + seconds 2<minutes> + 3<seconds>
Run Code Online (Sandbox Code Playgroud)
然后定义那些我将使用重载的转换函数,但它不如重新定义现有的二元运算符那么hacky.
这在F#中是不可能的.如果不指定类型的转换,则无法直接"自动转换"成功.您必须明确调用转换函数(seconds_per_minute等).
但是,Phil Trelford展示了一种机制,您可以通过该机制创建支持此功能的运行时类,但语法略有不同.使用他的类型,你可以写:
let duration = 1.0 * SI.hours + 2.0 * SI.minutes + 3.0 * SI.seconds
Run Code Online (Sandbox Code Playgroud)