F #: устранение избыточности в Map / Reduce / Filter

Допустим, у меня есть список и набор, и я хочу кое-что с ними сделать:

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)

Теперь, очевидно, A обрабатывает списки, а B - наборы . Однако меня очень раздражает необходимость писать List. List. снова и снова: это не только многословный, повторяющийся шаблон, который не передает никакой информации и мешает читать функциональность кода, это также де-факто аннотация типа, которую я должен отслеживать И синхронизируйтесь с остальной частью моего кода.

Я хочу иметь возможность делать что-то вроде следующего:

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)

Когда компилятор знает, что inA - это список, а inB - это набор, и, таким образом, все операции принадлежат правильному классу, и поэтому outA является список и outB - это набор. Я могу частично добиться этого с помощью Seq:

let map(x) =
    Seq.map(x)

let filter(x) =
    Seq.filter(x)

И я могу написать именно это. Проблема заключается в том, что он переводит все в последовательности, и я больше не могу выполнять над ними операции списка / набора. Точно так же

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)

также удаляет все это, но затем приводит все к IEnumerable.Мне удалось получить это довольно неплохо, преобразовав все статические методы в методы экземпляра с помощью расширений:

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)

но я подозреваю, что это приведет к проблемам с выводом типов, упомянутым здесь: Цепочка методов vs |> Оператор конвейера ? Я действительно не знаю; Я не знаком с тем, как работает алгоритм вывода типов.

Суть в том, что я собираюсь проделать чертовски много операций со списком / набором / отображением массива / уменьшением / фильтром, и я хочу, чтобы они выглядели как можно красивее и чистее. Прямо сейчас, помимо того, что меня отвлекают от важных битов в выражении (например, «карта» и лямбда), они также предоставляют де-факто аннотации типов в том месте, где компилятор должен хорошо знать, что это за коллекция. прохождение есть.

Более того, это именно тот тип вещей, для решения которого предназначены объектно-ориентированное наследование и полиморфизм, поэтому мне было интересно, существует ли какой-нибудь эквивалентный функциональный шаблон, который я не знаю, который решал бы его так же элегантно. Возможно, я мог бы выполнить проверку типа в моей статической карте и выполнить функцию соответствующего типа map на входе?

Есть ли у кого-нибудь лучшее решение, чем те, которые я уже использовал пробовал, или я натыкаюсь головой на фундаментальное ограничение механизма вывода типа F #, которое я должен просто принять и двигаться дальше?

13
задан Community 23 May 2017 в 12:06
поделиться