Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 352
Abel Avatar asked Feb 11 '23 03:02

Abel


1 Answers

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#?

like image 192
bytebuster Avatar answered Feb 16 '23 02:02

bytebuster