Допустим, у меня есть список и набор, и я хочу кое-что с ними сделать:
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 #, которое я должен просто принять и двигаться дальше?