Search code examples
compiler-errorsf#active-pattern

Multi-case parameterized active patterns returning error FS0722 Only active patterns returning exactly one result may accept arguments


Since I only found Japanese pages about this error, I figured, let's log it and ask here, since my Japanese is kinda rusty.

If I have the following FSharp active pattern (simplified example):

let (|InRange|OutOfRange|) from too =
    function
    | input when input >= from && input <= too -> InRange
    | _ -> OutOfRange

It compiles perfectly and shows its type as:

val ( |InRange|OutOfRange| ) :
  from:'a -> too:'a -> _arg1:'a -> Choice<unit,unit> when 'a : comparison

But when I try to use it, i.e. as follows, it throws an error:

let test i = match i with
             | InRange 10 20 -> "in range"
             | _ -> "out of range"

Throws: error FS0722: Only active patterns returning exactly one result may accept arguments

I can resolve it by turning it into two single-case parameterized active patterns, each returning None/Some(x), but I'm still wondering why I am not allowed doing so and/or whether there's syntax I can use that I am not aware of. I am also wondering why it compiles, but I cannot use it?


Solution

  • The simplest solution would be refactoring this into a partial active pattern:

    let (|InRangeInclusive|_|) lo hi x =
        if lo <= x && x <= hi then Some () else None
    

    Then you may even combine them in something like this:

    let test i = match i with
             | InRangeInclusive 10 20 -> "in first range"
             | InRangeInclusive 42 100 -> "in second range"
             | _ -> "out of range"
    

    Note, I took my liberty to give the pattern a better name, because those who would use your code may be confused about its behavior with corner cases.

    I'm still wondering why I am not allowed doing so?

    Why can't non-partial active patterns be parameterized in F#?