0

I have a 'sub state':

type SubState =
    | DoingA
    | DoingB
    | AFewMore

and a main state:

type State =
    | Initializing
    | DoingStuff of SubState
    | DoingNothing

and then I use that state in a match statement:

let state : State = ... 

match anotherState with
| hello -> ()
| hello when state = Initializing -> ()
| hello when state = DoingStuff -> ()   <- won't compile
| hello when state = DoingStuff _-> ()  <- won't compile either

so I have to add to my State a helper:

type State =
    | Initializing
    | DoingStuff of SubState
    | DoingNothing

    member this.IsDoingStuff =
        match this with
        | DoingStuff _ -> true
        | _ -> false

and then I can do my main match with:

match anotherState with
| hello -> ()
| hello when state = Initializing -> ()
| hello when state.IsDoingStuff -> () <- this works

but I would really like

| hello when state = DoingStuffAndIDontCareAboutTheSubState -> ()

Is there a nice syntactic way to the when condition and ignore the value of 'DoingStuff'?

I understand I could do:

match anotherState, state with
| hello, DoingStuff _ -> 

but in many cases, I don't need the second value, so I'm trying to find a solution where I can keep the when statement.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
Thomas
  • 10,933
  • 14
  • 65
  • 136
  • What's `someStuff` and why are you matching on it? – Mark Seemann Feb 03 '22 at 13:43
  • sorry, it should read 'anotherState', I'll edit the question – Thomas Feb 03 '22 at 13:44
  • Related: https://stackoverflow.com/questions/19001567/how-to-check-the-case-of-a-discriminated-union-with-fsunit – Mark Pattison Feb 03 '22 at 13:50
  • 1
    It's still not clear to me why the code is matching on `anotherState`, as it doesn't look like it's doing anything with it. To elaborate, with an unconditional match on a symbol like `hello`, that case is going to match *all* cases, and the subsequent cases will never be hit... if I understand the code correctly. – Mark Seemann Feb 03 '22 at 13:51
  • I guess my example is a bit too short, there is more than 'hello'; I wanted to illustrate that I've a match on a value and, in some cases a set of conditions but one of them is to match with another state. However I can't do "when state = DoingStuff _", I would have to enumerate all here, or make a helper method – Thomas Feb 03 '22 at 14:21

2 Answers2

4

There is no need to use match expressions. You can use the normal identifier pattern matching here:

let state anotherState =
    match anotherState with
    | Initializing -> ()
    | DoingStuff _ -> ()
    | DoingNothing ->

You can also nest these and check on the substate:

let state anotherState =
        match anotherState with
        | Initializing -> ()
        | DoingStuff DoingA -> ()
        | DoingStuff DoingB -> ()
        | DoingStuff AFewMore -> ()
        | DoingNothing ->

Match expressions are useful if you want to work with an expression inside your match case, e.g. suppose that you would have this:

type Foo =
   | Bar
   | Baz of int

let state foo =
   match foo with
   | Bar -> ()
   | Baz 0 -> ()
   | Baz 1 -> ()
   | Baz i when i < 10 -> ()
   | Baz _ -> ()
Tom Moers
  • 1,243
  • 8
  • 13
0

You're trying to use when for something you should be using pattern matching for; your last example is the idiomatic way to do this:

match anotherState, state with
| hello, DoingStuff _ -> 

when is for situations where you can't do this and significantly hurts the compiler's ability to do exhaustiveness checking.

This is all assuming that you're also pattern matching on anotherState in your actual code, otherwise that doesn't need to be part of the match.

Travis
  • 427
  • 4
  • 8