Как упоминал Брайан, использование @
обычно проблематично, поскольку оператор не может быть эффективно реализован для (простых) функциональных списков - ему необходимо скопировать весь первый список.
Я думаю, что Брианс предложил написать генератор последовательностей, который бы сразу генерировал список, но это немного сложнее.Вам нужно будет преобразовать список в массив, а затем написать что-то вроде:
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye) |> Array.ofList)
|> List.mapi (fun i l -> Array.init (2 * l.Length - 1) (fun n ->
if n < i || n - i >= l.Length then 0 else l.[n - i]))
|> List.reduce (Array.map2 (+))
В общем, если производительность важна, тогда вам, вероятно, все равно придется использовать массивы (потому что такого родапроблема может быть лучше всего решена путем доступа к элементам по индексу).Использовать массивы немного сложнее (нужно правильно настроить индексацию), но в F # это прекрасно подходит. В любом случае, если вы хотите написать это с использованием списков, то здесь есть несколько вариантов.Вы можете использовать выражения последовательности везде, которые будут выглядеть следующим образом:
let convolve y (x:_ list) =
[ for i, v1 in x |> List.zip [ 0 .. x.Length - 1] ->
[ yield! listFill i 0
for v2 in y do yield v1 * v2
yield! listFill (x.Length - i - 1) 0 ] ]
|> List.reduce (List.map2 (+))
... или вы также можете объединить эти два параметра и использовать вложенное выражение последовательности (с yield!
для создания нулей и списков)в лямбда-функции, которую вы передаете List.mapi
:
let convolve y x =
y |> List.map (fun ye -> x |> List.map ((*) ye))
|> List.mapi (fun i l ->
[ for _ in 1 .. i do yield 0
yield! l
for _ in 1 .. (l.Length - i - 1) do yield 0 ])
|> List.reduce (List.map2 (+))