Search code examples
f#discriminated-union

How to check if list contains discriminated union case with type?


Given the follwing code:

type Creature = 
    { Strength: int 
      Toughness: int }

type CardType = 
    | Creature of Creature
    | Land 
    | Instant

type Card = 
    { Types: CardType list }
module Card = 
    let isType t card = List.contains t card.Types


I am able to write

Card.isType Land

When trying to check if card is a creature, i get the following error:

This expression was expected to have type
    'CardType'    
but here has type
    'Creature -> CardType'

Is it even possible to have a "isType" function like this or am I stuck with pattern matching on a separate "isCreature" function instead?


Solution

  • Unless you want to resort to various reflection-based hacks, you are stuck with pattern matching. I would probably define a bit more general function using List.exist rather than List.contains (taking a predicate). Then you can easily define three functions for your specific card types:

    module Card = 
      let isType t card = 
        List.exists t card.Types
      
      let isCreature = 
        isType (function Creature _ -> true | _ -> false)
      let isLand = isType ((=) Land)
      let isInstant = isType ((=) Instant)
    

    For Land and Instant, you can just check if the value equals the specific one you're looking for. For Creature, this requires pattern matching - but can be done quite nicely using function.