Допустим, у меня есть список и набор, и я хочу с ними кое-что сделать:
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)
, но я подозреваю, что возникнут проблемы, связанные с выводом типов, упомянутые здесь: Метод Chaining vs |> Трубный оператор ?Я действительно не знаю;Я не знаком с тем, как работает алгоритм вывода типов.
Суть в том, что я полагаю, что собираюсь выполнять чертовски много из этих операций списка / набора / массива / уменьшения / фильтрации иЯ хочу, чтобы они выглядели максимально красиво и чисто.Прямо сейчас, кроме отвлечения меня от важных битов в выражении (то есть, «карта» и лямбда), они также предоставляют фактические аннотации типа в месте, где компилятор должен хорошо знать, что такое коллекция.прохождение в том.
Более того, это именно та вещь, которую должны решить наследование и полиморфизм ОО, поэтому мне было интересно, если бы существовал какой-то эквивалентный функциональный паттерн, который я не знаю, который бы решал его так же элегантно.Возможно, я мог бы выполнить проверку типа в своем собственном статическом map
и выполнить функцию map
соответствующего типа на входе?
Есть ли у кого-нибудь лучшее решение, чем те, которые я уже пробовал, или яврезаться мне в принципиальное ограничение механизма логического вывода типа F #, что я должен просто принять и двигаться дальше?