functional-programming - 在 F# 中模拟多态变体?
问题描述
我是 F# 的新手,所以如果这是一个愚蠢的问题或者语法可能有点不对,请提前原谅我。希望无论如何都能理解问题的要点。
我想要实现的是组合 egResult
的(或Either
类似的)具有不同错误类型(可区分联合)的可能性,而无需创建包含其他两个可区分联合的联合的显式可区分联合。
让我举一个例子。
假设我有一个Person
这样定义的类型:
type Person =
{ Name: string
Email: string }
假设您有一个验证名称的函数:
type NameValidationError =
| NameTooLong
| NameTooShort
let validateName person : Result<Person, NameValidationError>
另一个验证电子邮件地址:
type EmailValidationError =
| EmailTooLong
| EmailTooShort
let validateEmail person : Result<Person, EmailValidationError>
现在我想编写validateName
and validateEmail
,但问题是 中的错误类型Result
有不同的类型。我想要实现的是一个函数(或运算符),它允许我做这样的事情:
let validatedPerson = person |> validateName |>>> validateEmail
(|>>>
是“魔术运算符”)
通过使用|>>>
错误类型validatedPerson
将是NameValidationError
和的联合EmailValidationError
:
Result<Person, NameValidationError | EmailValidationError>
为了清楚起见,应该可以在组合链中使用任意数量的函数,即:
let validatedPerson : Result<Person, NameValidationError | EmailValidationError | XValidationError | YValidationError> =
person |> validateName |>>> validateEmail |>>> validateX |>>> validateY
在像ReasonML这样的语言中,您可以使用称为多态变体的东西,但这在 F# 中不可用。
是否有可能使用具有联合类型(或任何其他技术)的泛型以某种方式模仿多态变体?!或者这是不可能的?
解决方案
这可能比您想要的更冗长,但它确实允许您将内容放入 DU 中而无需明确定义它。
F# 的Choice
类型定义如下:
type Choice<'T1,'T2> =
| Choice1Of2 of 'T1
| Choice2Of2 of 'T2
type Choice<'T1,'T2,'T3> =
| Choice1Of3 of 'T1
| Choice2Of3 of 'T2
| Choice3Of3 of 'T3
// Going up to ChoiceXOf7
使用您现有的功能,您可以像这样使用它们:
// This function returns Result<Person,Choice<NameValidationError,EmailValidationError>>
let validatePerson person =
validateName person
|> Result.mapError Choice1Of2
|> Result.bind (validateEmail >> Result.mapError Choice2Of2)
这是您使用结果的方式:
let displayValidationError person =
match person with
| Ok p -> None
| Error (Choice1Of2 NameTooLong) -> Some "Name too long"
| Error (Choice2Of2 EmailTooLong) -> Some "Email too long"
// etc.
如果要添加第三个验证validatePerson
,则需要切换到Choice<_,_,_>
DU 案例,例如Choice1Of3
等等。
推荐阅读
- javascript - 表单的应用程序脚本返回无法读取未定义错误的属性“值”
- settings - Orbeon forms CE 中存储的数据库在哪里?
- pom.xml - 如何摆脱错误得到一个异常 - 在 checkstyle 中期待 EOF
- javascript - Angular 9 - 找不到管道“键值”
- android - 来自片段的自定义对话框片段
- javascript - Javascript 从一个 Promise 中设置一个全局变量
- python - 使用 YOLO 或其他图像识别技术来识别图像中存在的所有字母数字文本
- angular - 错误 cb() 从未调用过!- 执行 npm 安装时出错
- angular - 双向组合选择器,没有循环依赖
- java - 有没有一种新的技术来检测我们由 webdriver 控制的 chrome?