Simular variantes polimórficas en F #?

Johan:

Soy nuevo en F # así que perdónenme con antelación si se trata de una pregunta estúpida o si la sintaxis puede ser un poco apagado. Esperemos que sea posible entender la esencia de la cuestión de todos modos.

Lo que me gustaría lograr es la posibilidad de componer por ejemplo, Result's (o un Eithero algo similar) que tienen diferentes tipos de error (uniones discriminadas) sin la creación de una explícita unión discriminada que incluye la unión de los otros dos sindicatos discriminados.

Permítanme presentar un ejemplo.

Digamos que tengo un tipo Persondefinido de esta manera:

type Person =
    { Name: string
      Email: string }

Imagine que tiene una función que valida el nombre de:

type NameValidationError = 
  | NameTooLong
  | NameTooShort

let validateName person : Result<Person, NameValidationError>

y otro que valida una dirección de correo electrónico:

type EmailValidationError = 
  | EmailTooLong
  | EmailTooShort

let validateEmail person : Result<Person, EmailValidationError>

Ahora quiero componer validateNamey validateEmail, pero el problema es que el tipo de error en la Resultcuenta con diferentes tipos. Lo que me gustaría conseguir es una función (o el operador) que me permite hacer algo como esto:

let validatedPerson = person |> validateName |>>> validateEmail

( |>>>Es el "operador mágica")

Al utilizar |>>>el tipo de error de validatedPersonque sería una unión de NameValidationErrory EmailValidationError:

Result<Person, NameValidationError | EmailValidationError>

Sólo para que quede claro, debería ser posible para un número arbitrario uso de las funciones de la cadena de composición, es decir:

let validatedPerson : Result<Person, NameValidationError | EmailValidationError | XValidationError | YValidationError> = 
       person |> validateName |>>> validateEmail |>>> validateX |>>> validateY

En lenguajes como ReasonML se puede usar algo llamado variantes polimórficas , pero esto es no disponible en C # como afaict.

¿Sería posible que las variantes polimórficas de alguna manera imitan utilizando los genéricos con tipos de unión (o cualquier otra técnica) ?! O es imposible?

Asti:

Hay algunas interesantes propuestas de uniones de tipo borrados , lo que permite limitaciones unión anónima de tipo de imprenta.

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) 

El operador de la magia que le daría una NameValidationError | EmailValidationErrortendría su tipo sólo existen en tiempo de compilación. Que sería borrado de objecten tiempo de ejecución.

Pero sigue siendo en el yunque, así que tal vez todavía podemos tener algo de código legible por hacer el borrado de nosotros mismos?

El operador de composición podría 'borrado' (caja, en realidad) el tipo de error de resultado:

let (|>>) input validate = 
    match input with 
    | Ok(v) -> validate v |> Result.mapError(box) 
    | Error(e) -> Error(box e)        

y podemos tener un patrón activo parcial para hacer casos du type-juego agradable al paladar.

let (|ValidationError|_|) kind = function
    | Error(err) when Object.Equals(kind, err) -> Some () 
    | _ -> None

Ejemplo (con validaciones súper sesgada):

let person = { Name = "Bob"; Email = "[email protected] "}
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"
| _ -> ()

Esto derivará en validateVibe

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=370020&siteId=1
Recomendado
Clasificación