gpt4 book ai didi

functional-programming - 在 F# 中模拟多态变体?

转载 作者:行者123 更新时间:2023-12-03 09:31:03 24 4
gpt4 key购买 nike

我是 F# 新手,所以如果这是一个愚蠢的问题或者语法可能有点不对,请提前原谅我。希望无论如何都可以理解问题的要点。

我想要实现的是编写的可能性,例如Result的(或 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>

现在我要作曲 validateNamevalidateEmail ,但问题是 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 之类的语言中你可以使用名为 polymorphic variants 的东西但这是 not available in F#事实上。

是否有可能使用具有联合类型(或任何其他技术)的泛型以某种方式模拟多态变体?!或者这是不可能的?

最佳答案

有一些有趣的proposals for erased type unions ,允许 Typescript 风格的匿名联合约束。

type Goose = Goose of int
type Cardinal = Cardinal of int
type Mallard = Mallard of int

// a type abbreviation for an erased anonymous union
type Bird = (Goose | Cardinal | Mallard)

会给你一个 NameValidationError | EmailValidationError 的魔术运算符将使其类型仅在编译时存在。它将被删除到 object在运行时。

但它仍然在铁砧上,所以也许我们仍然可以通过自己删除来获得一些可读的代码?

组合运算符可以“删除”(实际上是框)结果错误类型:
let (|>>) input validate = 
match input with
| Ok(v) -> validate v |> Result.mapError(box)
| Error(e) -> Error(box e)

并且我们可以有一个部分事件模式来使类型匹配的 DU 案例变得可口。
let (|ValidationError|_|) kind = function
| Error(err) when Object.Equals(kind, err) -> Some ()
| _ -> None

示例(带有 super 偏向验证):
let person = { Name = "Bob"; Email = "bob@email.com "}
let validateName person = Result.Ok(person)
let validateEmail person = Result.Ok(person)
let validateVibe person = Result.Error(NameTooShort)

let result = person |> validateName |>> validateVibe |>> validateEmail

match result with
| ValidationError NameTooShort -> printfn "Why is your name too short"
| ValidationError EmailTooLong -> printfn "That was a long address"
| _ -> ()

这将在 validateVibe 上分流

关于functional-programming - 在 F# 中模拟多态变体?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60586666/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com