문제

If I have a discriminated union

type Result<'T,'U> =
| Success of 'T
| Failure of 'U

Then I can create a pattern matching function to test for success

let success = function
    | Success(_) -> true
    | _ -> false

Can I create this as a one liner, something like this?

let success = fun x -> x = Success(_)

This last line doesn't compile, but I think it demonstrates my intent

도움이 되었습니까?

해결책

There is no easy way to do so, but you could do it via reflection. Using the isUnionCase function from this answer, we can write:

let success = isUnionCase <@ Success @>

For this particular case, I think the success function is succinct enough to be qualified as one-liner:

let success = function Success _ -> true | _ -> false

As @Daniel said, compiler-generated Is* functions should be exposed. There is a related suggestion on User Voice, perhaps you should vote so that it is implemented in F# 4.0.

다른 팁

The compiled form exposes properties like IsSuccess/IsFailure for each case but, unfortunately for this scenario, they're only available in other .NET languages. What you have is as good as it gets.

Interestingly, trying to define those members will not work either:

type Result<'T,'U> =
    | Success of 'T
    | Failure of 'U
    member this.IsSuccess = true //ERROR

The member 'IsSuccess' can not be defined because the name 'IsSuccess' clashes with the default augmentation of the union case 'Success' in this type or module

Seems to me if they exist in F# in the sense that members with the same names can't be defined, they should be usable as well. Maybe a candidate for a pull request?

Noting that the Option type does have IsSome and IsNone properties, I looked at the source code and found that the type is decorated [<DefaultAugmentation(false)>].

Applying that attribute to the Result type, I found I was able to define an IsSuccess property. This attribute "turns off the generation of standard helper member tester, constructor and accessor members for the generated Common Language Infrastructure (CLI) class for that type," so use with caution.

You might also take another cue from the Option type and define a Result module, defining isSuccess and isFailure functions:

module Result =
    let isSuccess = function Success _ -> true | _ -> false
    let isFailure = function Failure _ -> true | _ -> false

You can create a generic function that helps you:

let ItIsSucess value =
  match value with
  | Success(_) -> true
  | _          -> false

Than you can write sth. like:

let expr = ...
if ItIsSucess expr than
  "do something"
else
  "do nothing"

You could also think about think like an even more generic function and use reflection to test against any types. But this is not easy and I do not recommand to do that for this simple task. Reflection could destroy the benefits of type safety in F#, so be aware if you use it.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top