F# 如何对度量单位进行分类?
问题很简单,我想计算一些旅行费用,包括丹麦克朗和日元的费用。因此,我找到了一种很好的建模货币的方法,以便能够来回转换:F# 如何对度量单位进行分类?,f#,F#,问题很简单,我想计算一些旅行费用,包括丹麦克朗和日元的费用。因此,我找到了一种很好的建模货币的方法,以便能够来回转换: [<Measure>] type JPY [<Measure>] type DKK type CurrencyRate<[<Measure>]'u, [<Measure>]'v> = { Rate: decimal<'u/'v>; Date: System.DateTime} let sep10
[<Measure>] type JPY
[<Measure>] type DKK
type CurrencyRate<[<Measure>]'u, [<Measure>]'v> =
{ Rate: decimal<'u/'v>; Date: System.DateTime}
let sep10 = System.DateTime(2015,9,10)
let DKK_TO_JPY : CurrencyRate<JPY,DKK> =
{ Rate = (1773.65m<JPY> / 100m<DKK>); Date = sep10}
let JPY_TO_DKK : CurrencyRate<DKK,JPY> =
{ Rate = (5.36m<DKK> / 100.0m<JPY>); Date=sep10 }
是否有一种将这些度量单位作为类别使用的好方法?比如说
[<Measure>] Length = Meter | Feet
[<Measure>] Currency = JPY | DKK | USD
[]长度=米|英尺
[]货币=日元|丹麦克朗|美元
还是我应该重新设计我的问题,也许不使用度量单位?关于第一个问题不,你不能,但我认为你不需要度量单位来解决你在第二个问题中所说的问题 想一想,您计划如何在运行时获取这些记录(用户输入、来自数据库、来自文件等),并记住度量单位是编译时特性,在运行时删除。除非这些记录总是硬编码的,否则会使你的程序毫无用处 我的感觉是,您需要在运行时处理这些货币,并将它们作为数据处理更为合理 例如,尝试在
费用中添加一个名为“货币”的字段:
type Expense = {
name: string
quantity: int
amount: decimal
currency: Currency
}
然后
作为Gustavo公认答案的替代方案,如果您仍然希望防止任何人和任何函数意外地将日元与丹麦克朗金额相加,您可以保留您的歧视性联盟的想法,如下所示:
let sep10 = System.DateTime(2015,9,10)
type Money =
| DKK of decimal
| JPY of decimal
type Expense = {
name: string
quantity: int
amount: Money
date : System.DateTime
}
type RatesTime = { JPY_TO_DKK : decimal ; DKK_TO_JPY : decimal ; Date : System.DateTime}
let rates_sep10Tosep12 = [
{ JPY_TO_DKK = 1773.65m ; DKK_TO_JPY = 5.36m ; Date = sep10}
{ JPY_TO_DKK = 1779.42m ; DKK_TO_JPY = 5.31m ; Date = sep10.AddDays(1.0)}
{ JPY_TO_DKK = 1776.07m ; DKK_TO_JPY = 5.33m ; Date = sep10.AddDays(2.0)}
]
let travel_expenses = [
{ name = "flight tickets"; quantity = 1; amount = DKK 5000m; date =sep10 }
{ name = "shinkansen ->"; quantity = 1; amount = JPY 10000m; date = sep10.AddDays(1.0)}
{ name = "shinkansen <-"; quantity = 1; amount = JPY 10000m ; date = sep10.AddDays(2.0)}
]
let IN_DKK (rt : RatesTime list) (e : Expense) =
let {name= _ ;quantity = _ ;amount = a ;date = d} = e
match a with
|DKK x -> x
|JPY y ->
let rtOfDate = List.tryFind (fun (x:RatesTime) -> x.Date = d) rt
match rtOfDate with
| Some r -> y * r.JPY_TO_DKK
| None -> failwith "no rate for period %A" d
let total_expenses_IN_DKK =
travel_expenses
|> List.fold(fun acc e -> (IN_DKK rates_sep10Tosep12 e) + acc) 0m
let sep10=系统日期时间(2015,9,10)
打字钱=
|十进制数
|十进制日元
类型费用={
名称:string
数量:整数
金额:货币
日期:System.DateTime
}
键入RatesTime={JPY_TO_DKK:decimal;DKK_TO_JPY:decimal;日期:System.DateTime}
让费率从SEP10到SEP12=[
{JPY_TO_DKK=1773.65万;DKK_TO_JPY=536万;日期=2010年9月}
{JPY_TO_DKK=1779.42万;DKK_TO_JPY=531万;日期=sep10.AddDays(1.0)}
{JPY_TO_DKK=1776.07万;DKK_TO_JPY=533万;日期=sep10.AddDays(2.0)}
]
让差旅费用=[
{name=“机票”;数量=1;金额=5000m丹麦克朗;日期=2010年9月}
{name=“新干线->”;数量=1;金额=10万日元;日期=sep10.AddDays(1.0)}
{name=“新干线第一号:没有办法做最后一件事——但你应该做的是选择一种基础货币,只列出这种类型的货币——在添加之前进行转换
type Money =
| DKK of decimal<DKK>
| JPY of decimal<JPY>
type Expense = {
name: string
quantity: int
amount: Money
}
let travel_expenses = [
{ name = "flight tickets"; quantity = 1; amount = DKK(5000m<DKK>) }
{ name = "shinkansen ->"; quantity = 1; amount = JPY(10000m<JPY>) }
{ name = "shinkansen <-"; quantity = 1; amount = JPY(10000m<JPY>) }
]
[<Measure>] Length = Meter | Feet
[<Measure>] Currency = JPY | DKK | USD
type Expense = {
name: string
quantity: int
amount: decimal
currency: Currency
}
type CurrencyRate = {
currencyFrom: Currency
currencyTo: Currency
rate: decimal
date: System.DateTime}
let sep10 = System.DateTime(2015,9,10)
type Money =
| DKK of decimal
| JPY of decimal
type Expense = {
name: string
quantity: int
amount: Money
date : System.DateTime
}
type RatesTime = { JPY_TO_DKK : decimal ; DKK_TO_JPY : decimal ; Date : System.DateTime}
let rates_sep10Tosep12 = [
{ JPY_TO_DKK = 1773.65m ; DKK_TO_JPY = 5.36m ; Date = sep10}
{ JPY_TO_DKK = 1779.42m ; DKK_TO_JPY = 5.31m ; Date = sep10.AddDays(1.0)}
{ JPY_TO_DKK = 1776.07m ; DKK_TO_JPY = 5.33m ; Date = sep10.AddDays(2.0)}
]
let travel_expenses = [
{ name = "flight tickets"; quantity = 1; amount = DKK 5000m; date =sep10 }
{ name = "shinkansen ->"; quantity = 1; amount = JPY 10000m; date = sep10.AddDays(1.0)}
{ name = "shinkansen <-"; quantity = 1; amount = JPY 10000m ; date = sep10.AddDays(2.0)}
]
let IN_DKK (rt : RatesTime list) (e : Expense) =
let {name= _ ;quantity = _ ;amount = a ;date = d} = e
match a with
|DKK x -> x
|JPY y ->
let rtOfDate = List.tryFind (fun (x:RatesTime) -> x.Date = d) rt
match rtOfDate with
| Some r -> y * r.JPY_TO_DKK
| None -> failwith "no rate for period %A" d
let total_expenses_IN_DKK =
travel_expenses
|> List.fold(fun acc e -> (IN_DKK rates_sep10Tosep12 e) + acc) 0m