4

I have a DU like this:

type Food =
| Beer
| Bacon
| Apple
| Cherry

I want to add a characteristic to the DU to flag if the food is a fruit or not. I first thought of something like this:

type NonFruit = NonFruit
type Fruit = Fruit

type Food =
| Beer of NonFruit
| Bacon of NonFruit
| Apple of Fruit
| Cherry of Fruit

And then a method like this:

let fruitChecker (myFood:Food) = match myFood with | :? NonFruit -> "No" | :? Fruit -> "yes"

But the compiler is yelling at me:

The type 'Food' does not have any proper subtypes and cannot be used as the source

Am I approaching the problem incorrectly?

Thanks

Jamie Dixon
  • 4,204
  • 4
  • 25
  • 47
  • possible duplicate of [F# modeling playing cards](http://stackoverflow.com/questions/29001670/f-modeling-playing-cards) – Mark Seemann Jul 27 '15 at 12:47

2 Answers2

9

Or, use Active Patterns: https://msdn.microsoft.com/en-us/library/dd233248.aspx

type Food =
| Beer
| Bacon
| Apple
| Cherry

let (|NonFruit|Fruit|) =
    function
    | Beer | Bacon -> NonFruit
    | Apple | Cherry -> Fruit

let fruitChecker = function | NonFruit -> "No" | Fruit -> "Yes"

[Beer;Bacon;Apple;Cherry] |> List.iter(fun x -> printfn "%s" (fruitChecker x))

Print:

No
No
Yes
Yes

Link: https://dotnetfiddle.net/oRYDs6

FoggyFinder
  • 2,230
  • 2
  • 20
  • 34
3

You should simply add a function for that. If you want to keep it "close" to the type, make it a static member:

type Food =
   | Beer
   | Bacon
   | Apple
   | Cherry
   static member IsFruit = function Beer | Bacon -> false | Apple | Cherry -> true

Think of the DU cases as constructors - it makes sense to pass in the name of the brewery to the Beer constructor, but whether it's a fruit or not is a static quality that is out of place there.

scrwtp
  • 13,437
  • 2
  • 26
  • 30