'Can I set a "is a Discriminated Union" type constraint on a generic argument in F# type declaration?
I am creating a type system for some generic types of common input:
// type Validator<'t> when 't :> ??? = Validator of 't
// with member x.validate value condition =
// if condition then
// (true, Some ('t value))
// else
// (false, None)
module Validatable =
let validate t value condition =
if condition then
(true, Some (t value))
else
(false, None)
type Email = Email of string
with member x.validate(s) = Validatable.validate Email s (Regex.IsMatch(s, ""))
type Name = Name of string
with member x.validate(s) = Validatable.validate Name s (Regex.IsMatch(s, ""))
type PhoneNumber = PhoneNumber of string
with member x.validate(s) = Validatable.validate PhoneNumber s (Regex.IsMatch(s, ""))
You'll see that within the comment, I have another type commented out. I am hoping to use the type defined within the comment to replace the functionality of the validate t value condition function within the Validatable module.
What do I need to replace the ??? with to allow me to say that the generic parameter 't is the case identifier of a Discriminated Union?
Solution 1:[1]
It is really hard to tell what are you actually trying to do. But if you want to write some function that works on multiple types of values, you generally can use interfaces and do not need generic type constraints.
For example, if you wanted to have a generic way of validating certain kinds of values using regular expressions, you could define an IValidable interface:
type IValidable =
abstract Value : string
abstract ValidationRegex : string
Then implement the interface in all the types you want to validate:
type Email =
| Email of string
interface IValidable with
member x.Value = let (Email v) = x in v
member x.ValidationRegex = "[a-z]+@[a-z]+.[a-z]+"
type PhoneNumber =
| PhoneNumber of string
interface IValidable with
member x.Value = let (PhoneNumber v) = x in v
member x.ValidationRegex = "[0-9]+"
And now you can write a simple validate function and use it with all your values:
let validate (v:IValidable) =
System.Text.RegularExpressions.Regex.IsMatch(v.Value, v.ValidationRegex)
validate (Email "no")
validate (Email "[email protected]")
validate (PhoneNumber "no")
validate (PhoneNumber "123")
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Tomas Petricek |
