MiP
MiP

Reputation: 6442

Downcast union cases without warning errors

How can I make compiler ignore some downcast pattern matching warnings (FS0025) but must capture other FS0025 warnings in the same file?

For example, the first pattern match (Student studentName) = john would never throw an error so I want the compiler to remove an unnecessary warning.

type Job = Student of string | Teacher of string

let john = Student "John"

(* FS0025: Incomplete pattern matches on this expression. For example,
the value 'Teacher _' may indicate a case not covered by the pattern(s). *)
let (Student studentName) = john
let (Teacher teacherName) = john // runtime error

I tried:

#nowarn "25"
let (Student studentName) = john
#warn "25"
let (Teacher teacherName) = john

But it doesn't show any warning error for let (Teacher teacherName) = john.

Upvotes: 2

Views: 86

Answers (3)

piaste
piaste

Reputation: 2058

Without access to GADTs, you have to add a bit of extra boilerplate in the form of an additional wrapper type:

type Student = Student of string 
type Teacher = Teacher of string

type Job = StudentJob of Student | TeacherJob of Teacher

let john = Student "John"

let (Student studentName) = john // no warning
let (Teacher teacherName) = john // compile error

Upvotes: 1

TheQuickBrownFox
TheQuickBrownFox

Reputation: 10624

In this particular example, both cases have the same data, a single name string, so you could pattern match to get the name:

let name = match john with Student n | Teacher n -> n

You could add this as a member on the type if you're going to do it many times:

type Job =
    | Student of string
    | Teacher of string
    member this.Name = match this with Student n | Teacher n -> n

let john = Student "John"
let name = john.Name

Upvotes: 1

gallais
gallais

Reputation: 12103

If you're willing to use a GADT to record in the type the constructor that was used you can write something like this (OCaml syntax, I don't have F# installed):

type student
type teacher

type _ job =
  | Student : string -> student job
  | Teacher : string -> teacher job

let john = Student "John"

Your first pattern-matching is then accepted without emitting a warning (it is total: there is only one constructor for a value of type student job):

let (Student studentName) = john

Whilst the second one is rejected at type-checking time because student and teacher are not equal:

let (Teacher teacherName) = john

You can write functions ranging over all jobs by writing functions from 'a job.

Upvotes: 2

Related Questions