Is it possible to pass discriminated union tags as arguments?

前端 未结 5 1403
不思量自难忘°
不思量自难忘° 2020-12-31 17:04

Is it possible to pass the type of a discriminated union tag to another function so it can use it for pattern matching?

Non working example of what I mean:



        
5条回答
  •  遥遥无期
    2020-12-31 17:50

    Just for completeness, I'll list this solution.
    If you quoted your input, you'd be able to reason about the names of the tags:

    open Microsoft.FSharp.Quotations
    
    type Animal = Pig of string | Cow of string | Fish of string
    
    let isAnimal (animalType : Expr) (animal : Expr) =
        match animal with
            | NewUnionCase(at, _) ->
                match animalType with
                    | Lambda (_, NewUnionCase (aatt, _)) -> aatt.Name = at.Name
                    | _ -> false
            | _ -> false
    
    let animal = <@ Pig "Mike" @>
    isAnimal <@ Pig @> animal  // True
    isAnimal <@ Cow @> animal  // False
    

    This is admittedly quite verbose though, and it would become even more so if you wanted to quote a list instead of a single value.

    A slightly different version, where we quote only the animal type, would let you easily filter lists of animals, as you need (at the price of some questionable comparison of strings):

    open Microsoft.FSharp.Quotations
    
    type Animal = Pig of string | Cow of string | Fish of string
    
    let isAnimal (animalType : Expr) animal =
        match animalType with
            | Lambda (_, NewUnionCase (aatt, _)) -> animal.ToString().EndsWith(aatt.Name)
            | _ -> false
    
    let animal = Pig "Mike"  // No quote now, so we can process Animal lists easily
    isAnimal <@ Pig @> animal  // True
    isAnimal <@ Cow @> animal  // False
    
    let animals = [Pig "Mike"; Pig "Sarah"; Fish "Eve"; Cow "Laura"; Pig "John"]
    let pigs = animals |> List.filter (isAnimal <@ Pig @>)
    

    The latter version is not really superior to passing the tag name as a string.

提交回复
热议问题