有没有更好的方法来编写下面的addValues
函数?似乎应该可以使用模式匹配而不是FSharp.Reflection但我看不到它。
open System
open FSharp.Reflection
type Value =
| Tag1 of decimal
| Tag2 of decimal
| Error of string
let addValues v1 v2 =
let c1, f1 = FSharpValue.GetUnionFields(v1, v1.GetType())
let c2, f2 = FSharpValue.GetUnionFields(v2, v2.GetType())
let amt1 = (f1.[0]) :?> decimal
let amt2 = (f2.[0]) :?> decimal
if c1 = c2
then ((FSharpValue.MakeUnion(c1, [|box (amt1 + amt2)|]))) :?> Value
else Error "Mixed Tags"
这可以这样使用:
addValues (Tag1 22m) (Tag1 10m) //Value = Tag1 32M
addValues (Tag1 22m) (Tag2 10m) //Value = Error "Mixed Tags"
答案 0 :(得分:5)
不清楚应该如何处理addValues (Error "e1") (Error "e2)
,但对于其他情况你可以这样做:
let addValues v1 v2 =
match v1, v2 with
| Tag1 d1, Tag1 d2 -> Tag1 (d1 + d2)
| Tag2 d1, Tag2 d2 -> Tag2 (d1 + d2)
| Error e1, Error e2 -> //???
| _ -> Error "Mixed Tags"
答案 1 :(得分:4)
这不正是原始问题的内容,但是 - 正如其他一些评论者所说的那样 - 我预感到您的数据类型并没有被很好地选择。拥有Application.Run
个案意味着,当您拥有更多标签时,您的Error
功能会变得非常尴尬。如果我假设你的所有值都是十进制的,你可以重新定义如下:
addValues
(或使用其中一种type Tag = | Tag1 | Tag2
type ResultOrError = | Result of Tag * decimal | Error of string
类型)。 Choice
然后成为:
addValues
当您将代码类型扩展为let addValues t1 t2 =
match t1, t2 with
| Result (tag1, v1), Result (tag2, v2) when tag1 = tag2 -> Result (tag1, v1 + v2)
| Result _, Result _ -> Error "Tag mismatch"
| Result _, Error _ -> failwith "not implemented"
| Error _, _ -> failwith "not implemented"
时,type Tag = | Tag1 | Tag2 | Tag3
仍然有效。
答案 2 :(得分:1)
我想和Anton Schwaighofer in his answer一样吹小号。关键信息必须在数据结构中,因为这将利用monad技术来做the lifting;此外,您还需要单独调用案例Tag1
和Tag2
的构造函数。
type Tag = Tag1 | Tag2
type ResultOrError =
| Result of Tag * decimal
| Error of string
let bind2 f = function
| Result(tag, value) -> f tag value
| error -> error
let lift2EqualTag op mx my =
bind2 (fun tagX x ->
bind2 (fun tagY y ->
if tagX = tagY then Result(tagX, op x y)
else Error "Mixed tags" ) my ) mx
let add = lift2EqualTag (+)
add (Result(Tag1, 22m)) (Result(Tag1, 10m))
// val it : ResultOrError = Result (Tag1,32M)
add (Result(Tag1, 22m)) (Result(Tag2, 10m))
// val it : ResultOrError = Error "Mixed tags"