Итак, давайте начнем с лучшего примера ... и угадайте, что вы ищете
позволяет определенному добавлению вот так ... сделать явным, что он работает с 2-мя кортежами ... не карри.
let addUp : (int * int) -> int =
fun (x,y) -> x + y
и ты хочешь идти (скажем)
let z = (2,4)|> (fun (x,y) -> 2*x,y) |> addUp
что некрасиво.
но обратите внимание, мы создаем конвейер, который преобразует 2 кортежа, а затем применяем к нему некоторую функцию.
Теперь кортеж - это «функтор» ... что означает, что когда мы получаем функцию, которая работает с типом внутри кортежа, мы можем преобразовать (поднять) его в функцию, которая работает со всем кортежем.
2 Кортеж дважды является функтором;
module TupleFst =
let map : ('a -> 'b) -> ('a * 'c) -> ('b * 'c) =
fun f (x,y) -> (f x, y)
module TupleSnd =
let map : ('a -> 'b) -> ('c * 'a) -> ('c * 'b) =
fun f (x,y) -> (x,f y)
Я определил их с помощью подписей, чтобы было понятно, что происходит.
В TupleFst мы берем функцию, которая работает с первым элементом кортежа, и «поднимаем» ее в функцию, которая работает со всем кортежем (который отображает первый элемент).
В TupleSnd мы делаем второй член кортежа.
теперь мы можем записать пример как ....
let z = (2,4)|> TupleFst.map ((*) 2) |> addUp
что лучше? ... спорно ... в этом тривиальном примере это, вероятно, делает жизнь хуже, но принцип там .... если вы посмотрите на FSharpPlus в функторах и аппликативном Theres гораздо больше на нем ... .и это может быть применено ко всем видам структур данных.
Я думаю, что пакет использует тот же синтаксис, украденный из Haskell, где, я думаю, вы можете написать выше:
let z = ((*) 2) <!> (2,4) |> addUp
но я не установил его и заставил все это работать ... так что в приведенном выше тексте может быть опечатка (ах ... я не уверен, как сказать FSharpPlus, какой функтор выбрать "map") from ... так что вышеприведенное неоднозначно и, вероятно, не компилируется ... вы, конечно, можете определить свой собственный оператор вместо "map")
let (<!>) = TupleFst.map
let (<!!>) = TupleSnd.map
let z1 = ((*) 2) <!> (2,4) |> addUp
let z2 = ((*) 2) <!!> (2,4) |> addUp
это компилирует "!" действует на 1-й элемент в кортеже "!!" на втором .... (я не уверен, что "!!" - разумное имя ... в то время как "!" идиоматично ... но что угодно)
(в данном случае это все излишне! ... другие ответы лучше ... Я думаю, что я пытался продемонстрировать, что если вы работаете в приподнятом мире (здесь кортежи), вы можете часто скрывать plumbling).