F# 匹配受歧视的联合案例而不是内容
在F#中,是否有可能根据案例而不是案例内容匹配受歧视的工会?例如,如果我想按大小写为F# 匹配受歧视的联合案例而不是内容,f#,pattern-matching,discriminated-union,F#,Pattern Matching,Discriminated Union,在F#中,是否有可能根据案例而不是案例内容匹配受歧视的工会?例如,如果我想按大小写为标志的元素筛选列表,是否可以这样筛选?目前,我被迫有三个独立的功能来过滤我想要的方式。这是我迄今为止的做法: type Option = {Id : string Arg : string} type Argument = | Flag of string | Option of Option | Unannotated of string //This is what
标志的元素筛选列表,是否可以这样筛选?目前,我被迫有三个独立的功能来过滤我想要的方式。这是我迄今为止的做法:
type Option =
{Id : string
Arg : string}
type Argument =
| Flag of string
| Option of Option
| Unannotated of string
//This is what I'm going for, but it does not work as the "other" match case will never be matched
let LocateByCase (case:Argument) (args : Argument List) =
args
|> List.filter (fun x -> match x with
| case -> true
| _ -> false)
let LocateAllFlags args =
args
|> List.filter (fun x -> match x with
| Flag y -> true
| _ -> false)
let LocateAllOptions args =
args
|> List.filter (fun x -> match x with
| Option y -> true
| _ -> false)
let LocateAllUnannotated args =
args
|> List.filter (fun x -> match x with
| Unannotated y -> true
| _ -> false)
我是否遗漏了F#语言的某些方面,这些方面会使这更容易处理?没有内置的方法来找出DU值的情况。面对此类要求时,通常的方法是为每种情况提供适当的功能:
type Argument =
| Flag of string
| Option of Option
| Unannotated of string
with
static member isFlag = function Flag _ -> true | _ -> false
static member isOption = function Option _ -> true | _ -> false
static member isUnannotated = function Unannotated _ -> true | _ -> false
let LocateByCase case args = List.filter case args
let LocateAllFlags args = LocateByCase Argument.isFlag args
(不用说,LocateByCase
函数实际上是多余的,但我决定保留它以使答案更清楚)
警告:下面是肮脏的黑客
或者,您可以将案例作为引用提供,并使自己成为一个函数,该函数将分析该引用,从中提取案例名称,并将其与给定值进行比较:
open FSharp.Quotations
let isCase (case: Expr<'t -> Argument>) (value: Argument) =
match case with
| Patterns.Lambda (_, Patterns.NewUnionCase(case, _)) -> case.Name = value.GetType().Name
| _ -> false
// Usage:
isCase <@ Flag @> (Unannotated "") // returns false
isCase <@ Flag @> (Flag "") // returns true
打开FSharp.quotes
让isCase(case:Expr(标志“xyz”)//返回true!
isCase let x=“abc”in Flag x@>(Flag“xyz”)//返回false.WTF?
//等等。。。
如果未来版本的编译器决定以稍有不同的方式生成引用,并且您的代码无法识别它们并始终报告错误否定,则可能会发生另一个问题
如果可能的话,我建议尽量避免混淆引文。表面上看起来很容易,但实际上是这样的。有趣的是,这实际上可以从C#轻松完成,但F#隐藏了使之容易的方法。尽管如此,你倾向于使用Flag
,而不是Flag y
从现在开始,我将在我的代码中这样做。我仍在学习:)有趣的东西,谢谢!您能解释一下带静态成员的位是什么吗?这就像C#中的对象方法吗?是的,它只是在您的类型上声明一个静态方法。因为您似乎是初学者,这里有一个建议:F#是一种非常好的语言。如果您发现自己试图绕过F#,那么极有可能您的数据建模错误。
let LocateByCase case args = List.filter (isCase case) args
let LocateAllFlags args = LocateByCase <@ Flag @> args
isCase <@ fun() -> Flag "abc" @> (Flag "xyz") // Returns true!
isCase <@ fun() -> let x = "abc" in Flag x @> (Flag "xyz") // Returns false. WTF?
// And so on...