我可以在 F# 类型声明中对泛型参数设置 "is a Discriminated Union" 类型约束吗?
Can I set a "is a Discriminated Union" type constraint on a generic argument in F# type declaration?
我正在为一些通用类型的通用输入创建一个类型系统:
// 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, ""))
您会看到在评论中,我注释掉了另一种类型。我希望使用注释中定义的类型来替换 Validatable
模块中 validate t value condition
函数的功能。
我需要更换什么???允许我说通用参数 't
是区分联合的案例标识符?
联合案例不是类型,它是产生类型值的函数。所以你可以这样写你的 Validator
类型:
type Validator<'inp, 'out> = Validator of ('inp -> 'out)
with member x.validate value condition =
let (Validator f) = x
if condition then
(true, Some (f value))
else
(false, None)
并像这样使用它:
type Email = Email of string
with member x.validate(s) = (Validator Email).validate s (Regex.IsMatch(s, ""))
type Name = Name of string
with member x.validate(s) = (Validator Name).validate s (Regex.IsMatch(s, ""))
type PhoneNumber = PhoneNumber of string
with member x.validate(s) = (Validator PhoneNumber).validate s (Regex.IsMatch(s, ""))
真的很难说清楚你到底想做什么。但是如果你想写一些作用于多种类型值的函数,你通常可以使用接口并且不需要泛型类型约束。
例如,如果您想要使用正则表达式验证某些类型的值的通用方法,您可以定义一个 IValidable
接口:
type IValidable =
abstract Value : string
abstract ValidationRegex : string
然后在所有要验证的类型中实现接口:
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]+"
现在您可以编写一个简单的 validate
函数并将其与您的所有值一起使用:
let validate (v:IValidable) =
System.Text.RegularExpressions.Regex.IsMatch(v.Value, v.ValidationRegex)
validate (Email "no")
validate (Email "no@no.no")
validate (PhoneNumber "no")
validate (PhoneNumber "123")
我正在为一些通用类型的通用输入创建一个类型系统:
// 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, ""))
您会看到在评论中,我注释掉了另一种类型。我希望使用注释中定义的类型来替换 Validatable
模块中 validate t value condition
函数的功能。
我需要更换什么???允许我说通用参数 't
是区分联合的案例标识符?
联合案例不是类型,它是产生类型值的函数。所以你可以这样写你的 Validator
类型:
type Validator<'inp, 'out> = Validator of ('inp -> 'out)
with member x.validate value condition =
let (Validator f) = x
if condition then
(true, Some (f value))
else
(false, None)
并像这样使用它:
type Email = Email of string
with member x.validate(s) = (Validator Email).validate s (Regex.IsMatch(s, ""))
type Name = Name of string
with member x.validate(s) = (Validator Name).validate s (Regex.IsMatch(s, ""))
type PhoneNumber = PhoneNumber of string
with member x.validate(s) = (Validator PhoneNumber).validate s (Regex.IsMatch(s, ""))
真的很难说清楚你到底想做什么。但是如果你想写一些作用于多种类型值的函数,你通常可以使用接口并且不需要泛型类型约束。
例如,如果您想要使用正则表达式验证某些类型的值的通用方法,您可以定义一个 IValidable
接口:
type IValidable =
abstract Value : string
abstract ValidationRegex : string
然后在所有要验证的类型中实现接口:
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]+"
现在您可以编写一个简单的 validate
函数并将其与您的所有值一起使用:
let validate (v:IValidable) =
System.Text.RegularExpressions.Regex.IsMatch(v.Value, v.ValidationRegex)
validate (Email "no")
validate (Email "no@no.no")
validate (PhoneNumber "no")
validate (PhoneNumber "123")