gpt4 book ai didi

f# - 带有十进制选项类型的算术

转载 作者:行者123 更新时间:2023-12-01 22:59:42 24 4
gpt4 key购买 nike

我正在尝试使用 decimal options 对自定义类型进行一些数学运算:

type LineItem = {Cost: decimal option; Price: decimal option; Qty: decimal option}

let discount = 0.25M

let createItem (c, p, q) =
{Cost = c; Price = p; Qty = q}

let items =
[
(Some 1M , None , Some 1M)
(Some 3M , Some 2.0M , None)
(Some 5M , Some 3.0M , Some 5M)
(None , Some 1.0M , Some 2M)
(Some 11M , Some 2.0M , None)
]
|> List.map createItem

我可以做一些非常简单的算术
items
|> Seq.map (fun line -> line.Price
|> Option.map (fun x -> discount * x))

这给了我
val it : seq<decimal option> =
seq [null; Some 0.500M; Some 0.750M; Some 0.250M; ...]

如果我尝试实际计算我需要的东西
items
|> Seq.map (fun line -> line.Price
|> Option.map (fun x -> discount * x)
|> Option.map (fun x -> x - (line.Cost
|> Option.map (fun x -> x)))
|> Option.map (fun x -> x * (line.Qty
|> Option.map (fun x -> x))))

我收到错误
error FS0001: Type constraint mismatch. The type 
'a option
is not compatible with type
decimal
The type ''a option' is not compatible with the type 'decimal'

我本来希望有一个 seq<decimal option>

我一定是遗漏了什么,但我似乎无法发现我遗漏了什么。

最佳答案

您遇到的一个问题是以下代码:

(line.Cost |> Option.map (fun x -> x))

lambda函数 (fun x -> x)已经存在。这是 id 函数。它只会返回您未更改的任何内容。您也可以编写这样的代码:

(line.Cost |> Option.map id)

接下来的事情。映射到 id 函数是没有意义的。您解开选项中的任何内容,对其应用 id 函数。什么根本没有改变小数点。然后你再次将小数包裹在一个选项中。你也可以只写:

line.Cost

并完全删除 Option.map 因为它什么都不做。

所以你在这里的代码:

|> Option.map (fun x -> x - (line.Cost |> Option.map (fun x -> x)))

等同于:

|> Option.map (fun x -> x - line.Cost)

这显然不起作用,因为在这里您尝试用 x a decimal 减去 line.Cost a option decimal 。所以你会得到一个类型错误。

我想你真正想要做的是在 line.Cost 存在的情况下从 line.Price 中减去 line.Cost,否则你想保持 line.Price 不变。

一种方法是为 line.Costs 提供一个可以使用的默认值,并且对减法没有影响。例如,如果 0line.Costs ,您可以使用值 None 进行减法。

所以你也可以写这样的东西:

|> Option.map (fun x -> x - (defaultArg line.Cost 0m))

乘法的默认值是 1m 。所以你总体结束。

items
|> Seq.map (fun line ->
line.Price
|> Option.map (fun x -> discount * x)
|> Option.map (fun x -> x - (defaultArg line.Cost 0m))
|> Option.map (fun x -> x * (defaultArg line.Qty 1m)))

例如上面的代码返回:

[None; Some -2.500M; Some -21.250M; Some 0.500M; Some -10.500M]

如果您的目标是将整个计算转化为 None值为 None 。我只想添加 map2 作为辅助函数。

module Option =
let map2 f x y =
match x,y with
| Some x, Some y -> Some (f x y)
| _ -> None

那么你就可以写:

items
|> List.map (fun line ->
line.Price
|> Option.map (fun price -> price * discount)
|> Option.map2 (fun cost price -> price - cost) line.Cost
|> Option.map2 (fun qty price -> price * qty) line.Qty)

它会返回:

[None; None; Some -21.250M; None; None]

关于f# - 带有十进制选项类型的算术,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39708745/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com