Digamos que tengo una lista y un conjunto y quiero hacer algunas cosas con ellos:F #: matar redundancia en un mapa/Reducir/Filtro
let outA = inA |> List.map(fun x -> x + 1) |> List.filter(fun x -> x > 10)
let outB = inB |> Set.map(fun x -> x + 1) |> Set.filter(fun x -> x > 10)
Ahora, obviamente, que maneja las listas A y B se encarga de conjuntos. Sin embargo, me resulta muy molesto tener que escribir List.
List.
una y otra vez: no solo es una repetición repetitiva y prolija que no transmite información y obstaculiza la lectura de la funcionalidad del código, sino que también es de facto. escriba la anotación de la que tengo que hacer un seguimiento y mantenerme sincronizado con el resto de mi código.
Lo que yo quiero ser capaz de hacer es algo como lo siguiente:
let outA = inA |> map(fun x -> x + 1) |> filter(fun x -> x > 10)
let outB = inB |> map(fun x -> x + 1) |> filter(fun x -> x > 10)
Con el compilador sabiendo que inA es una lista y INB es un conjunto, y por lo tanto todas las operaciones son de la clase correcta y, por lo tanto, outA es una lista y outB es un conjunto. Puedo lograr esto parcialmente con Seq:
let map(x) =
Seq.map(x)
let filter(x) =
Seq.filter(x)
Y puedo escribir exactamente eso. El problema con esto es que convierte todo en Secuencias, y ya no puedo realizar operaciones de lista/configuración en ellas. Del mismo modo,
let outA = inA.Select(fun x -> x + 1).Where(fun x -> x > 10)
let outB = inB.Select(fun x -> x + 1).Where(fun x -> x > 10)
También elimina todo eso, pero luego echa todo a IEnumerable. He conseguido que sea muy agradable mediante la conversión de todos los métodos estáticos en los métodos de instancia a través de extensiones:
type Microsoft.FSharp.Collections.List<'a> with
member this.map(f) = this |> List.map(f)
member this.filter(f) = this |> List.filter(f)
let b = a.map(fun x -> x + 1).filter(fun x -> x > 10)
pero sospecho que se ejecutará en los problemas tipo de inferencia que se mencionan aquí: Method Chaining vs |> Pipe Operator? Realmente no lo sé; No estoy familiarizado con el funcionamiento del algoritmo de inferencia tipo.
La conclusión es que creo que voy a estar haciendo muchísimas operaciones de estas listas/set/array map/reducir/filtrar y quiero que se vean tan bonitas y limpias como sea posible. En este momento, además de distraerme de los bits importantes en la expresión (es decir, el "mapa" y la lambda) también proporcionan anotaciones de tipo de facto en un lugar donde el compilador debería saber muy bien de qué colección estoy pasar es.
Además, este es exactamente el tipo de cosa que la herencia OO y el polimorfismo debe resolver, así que me preguntaba si había algún patrón funcional equivalente que no sé que lo resolvería tan elegantemente. Tal vez podría hacer una verificación de tipo en mi propio estático map
y realizar la función del tipo relevante map
en la entrada?
¿Alguien tiene alguna solución mejor que las que ya he probado, o me estoy enfrentando a una limitación fundamental del motor de inferencia tipo F #, que debería aceptar y seguir?
En mi opinión, la El nombre del módulo hace que el código sea más descriptivo. Usted sabe que es una Lista/Conjunto, simplemente mirando el código. – ebb
Básicamente quieres clases de tipo :) Pagar Haskell, o permanecer con nosotros y utilizar nombres calificados. –
@ebb: Pero el punto de la inferencia de tipo era que no necesitaba describir el código tanto = D. –