F# - Как удобно применять элементы в списке к параметрам частичной функции?
Предполагается, что есть список:
let lst = [1;2;3]
И частичная функция:
let addAll a b c =
a + b + c
Как можно удобно ввести параметры для частичной функции, используя элементы в списке lst
?
Один из способов сделать это:
addAll (lst |> List.item 0) (lst |> List.item 1) (lst |> List.item 2)
Но это не очень хорошо масштабируется! Кроме того, это скучно.
2 ответа
Другой вариант - использовать сопоставление с образцом:
let lst = [1;2;3]
match lst with [ a ; b; c] -> addAll a b c |_-> 0
возвращается 6
, Если lst не имеет ровно 3 элемента, он возвращает 0
но вы можете изменить его для обработки других случаев:
let callAddAll lst =
match lst with
| [ ] -> 0
| [ a ] -> addAll a 0 0
| [ a ; b ] -> addAll a b 0
| [ a ; b ; c ] -> addAll a b c
| a :: b :: c :: rest -> addAll a b c // ignore rest
[ ] |> callAddAll |> printfn "lst = %d" // = 0
[1 ] |> callAddAll |> printfn "lst = %d" // = 1
[1;2 ] |> callAddAll |> printfn "lst = %d" // = 3
[1;2;3 ] |> callAddAll |> printfn "lst = %d" // = 6
[1;2;3;4] |> callAddAll |> printfn "lst = %d" // = 6
Трудно сказать из ограниченного примера, каков ваш реальный вариант использования. Списки составлены так, чтобы содержать различное количество элементов, а функции занимают постоянное количество элементов, поэтому они не соответствуют друг другу. Возможно, имеет смысл использовать кортеж, а не список:
let tup = (1,2,3)
let addAll (a, b, c) =
a + b + c
addAll tup
Кортежи содержат фиксированное количество элементов, но они могут быть легко сконструированы и деконструированы и позволяют передавать все параметры вашей функции одновременно.
Вы также можете сделать то, что вы просили об использовании отражения, но это может сломаться в будущих версиях F#, и это почти никогда не будет хорошим дизайном для такого простого случая, как этот. Это также медленно и, как вы можете видеть по количеству downcast и бокса, это также не очень безопасно:
let lst = [1;2;3]
let addAll a b c =
a + b + c
let addAllVal = addAll
let f = addAllVal.GetType().GetMethod("Invoke", [| typeof<int>; typeof<int>; typeof<int> |])
let res = f.Invoke(addAllVal, Array.map box (Array.ofList lst)) :?> int