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
Другие вопросы по тегам