Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto implement partial active recognizers for DU cases #766

Open
gusty opened this issue Jul 7, 2019 · 6 comments

Comments

@gusty
Copy link

commented Jul 7, 2019

Auto implement partial active recognizers for DU cases

I propose we add a way to auto-implement partial active recognizers for DU cases. This will provide a way to treat patterns as first class functions.

The existing way of approaching this problem in F# is to implement some functions by hand:

type Cases = CaseA of int | CaseB of float | CaseC of (int * string)
let fCaseA = function | CaseA x -> Some x | _ -> None
let fCaseB = function | CaseB x -> Some x | _ -> None
let fCaseC = function | CaseC x -> Some x | _ -> None

Pros and Cons

The advantages of making this adjustment to F# are: less typing, less code that adds nothing but noise that hides the intent in the end.

The disadvantages of making this adjustment to F# are that it's work (RFC, PR, testing).

Extra information

Estimated cost (S):

Related suggestions: #611 specifically this suggestion was mentioned by @mexx comment there.

Affidavit (please submit!)

Please tick this by placing a cross in the box:

  • This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
  • I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • [?] This is not a breaking change to the F# language design (it will depend on the implementation we choose)
  • I or my company would be willing to help implement and/or test this

Some context

The case exposed in #611 is a good example of how useful this is and how it relates to treat patterns as first class functions.

I also find this boiler-plate code while defining CODECs for discriminated unions to Json in Fleece by using alternatives:

type Shape =
    | Rectangle of width : float * length : float
    | Circle of radius : float
    | Prism of width : float * float * height : float
    with 
        static member JsonObjCodec =
            jchoice
                [
                    Rectangle <!> jreq "rectangle" (function Rectangle (x, y) -> Some (x, y) | _ -> None)
                    Circle    <!> jreq "radius"    (function Circle x -> Some x | _ -> None)
                    Prism     <!> jreq "prism"     (function Prism (x, y, z) -> Some (x, y, z) | _ -> None)
                ]

And I'm sure that there might be more cases around.

Proposed syntax

The most obvious syntax I can think of is just the case enclosed in banana parens, ie (|CaseA|_|) which matches the syntax for partial active patterns, that's why I choose the title of this suggestion as auto-generate partial active patterns.

So it will be as if these functions:

let (|Rectangle|_|) = function | Rectangle x -> Some x | _ -> None
let (|Circle|_|) = function | Circle x -> Some x | _ -> None
let (|Prism|_|) = function | Prism x -> Some x | _ -> None

were generated automatically after the type declaration, then the above code could be reduced to:

type Shape =
    | Rectangle of width : float * length : float
    | Circle of radius : float
    | Prism of width : float * float * height : float
    with 
        static member JsonObjCodec =
            jchoice
                [
                    Rectangle <!> jreq "rectangle" (|Rectangle|_|)
                    Circle    <!> jreq "radius"    (|Circle|_|)
                    Prism     <!> jreq "prism"     (|Prism|_|)
                ]

Alternative syntax

Another possibility is to use a different syntax, not related to partial active patterns, but the essence of this suggestion is not the syntax itself but the possibility to auto-generate those functions automatically.

@realvictorprm

This comment has been minimized.

Copy link
Member

commented Jul 7, 2019

I really like this! This is a good addition in my opinion and should be easy to do :)

@pblasucci

This comment has been minimized.

Copy link

commented Jul 7, 2019

@gusty just to clarify...

Did you mean to specify partial active patterns? Because that seems like a better fit here. Emitting a single-case total active pattern seems like it wouldn’t really serve the highlighted use case.

@gusty gusty changed the title Auto implement active recognizers for DU cases Auto implement partial active recognizers for DU cases Jul 7, 2019

@gusty

This comment has been minimized.

Copy link
Author

commented Jul 7, 2019

Thanks @pblasucci I updated the suggestion title and also updated the content to reflect it.

@cartermp

This comment has been minimized.

Copy link
Member

commented Jul 8, 2019

This is a very interesting suggestion. We would have to consider compatibility here, likely only generating these functions if there isn't such an active recognizer name already in scope. But what if only a subset is in scope, do we still generate the remainders?

@gusty

This comment has been minimized.

Copy link
Author

commented Jul 8, 2019

@cartermp good catch, I will update the breaking change box, as it will depend on the implementation.

I would say that either:

  1. We always generate, it would be a breaking change when the same active recognizer identifiers were already in scope, but we can use the language switch

  2. We do as you say, we detect if they are in scope and either don't generate any active recognizer, or we generate only those that are not in scope.

  3. We use a different syntax than the proposed here, namely a syntax which is currently invalid, this way it's not a breaking change at all.

@charlesroddie

This comment has been minimized.

Copy link

commented Jul 9, 2019

An alternative to creating many new methods and names:

trymatch du with CaseA x -> x
tryfunction CaseA x -> x

Equivalent to:

match du with CaseA x -> Some x | _ -> None
function CaseA x -> Some x | _ -> None

Pros: Doesn't create so many new methods and names. Deals with user-defined patterns, and more than one if needed. Fewer characters than current syntax.
Cons: more characters than proposed syntax (although the proposed syntax may need to be made slightly more verbose for clarity).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.