[Перевод] F#6: Кортежи

Итак, наше путешествие в F # продолжается. Следующая статья будет посвящена типам F #, которые могут иметь или не иметь стандартные эквиваленты .NET. Этот пост о кортежах.

Что такое кортежи


Кортеж — это группа неназванных, но упорядоченных значений, возможно, разных типов.

Создание кортежей


Кортежи очень легко создавать, мы просто делаем что-то вроде показанного ниже. Обратите внимание, как я создал смешанный пакет кортежей, некоторые значения из которых являются числами, а другие являются строками, и мы также можем смешивать и сопоставлять как типы, так и количество значений.

let a = (1,2)
let b = (1,"cat")
let c = (1,"cat")
let d = (1,"cat", 'c')


Универсальные кортежи


Функции, принимающие кортежи, могут также принимать универсальные кортежи без каких-либо проблем. Система логического вывода типа F # с удовольствием справится с выводом правильных типов для кортежа. Вот пример.

let someFunction tup = 
    let (x,y) = tup
    printfn "x is %A and y is %A" x y
 
do someFunction ("cat","dog")
do someFunction (11,12)


И вот результаты выполнения выше, где можно увидеть, что функция someFunction без проблем принимала и работала с различными типизированными кортежами.

image

Сигнатуры кортежей


До сих пор мы вообще не касались понимания сигнатур F#, на самом деле это тема, которой я тоже решил посвятить целое сообщение в блоге, так как я считаю, что он достаточна сложна. Однако мы находимся там, где мы есть, то есть здесь и сейчас, и мы изучаем кортежи, поэтому сейчас я просто хотел продемонстрировать, как будет выглядеть сигнатура кортежа.

Допустим, я объявил следующие кортежи в окне FSI:

let a = (1,2)
let b = (1,"codfather")
let c = (1,"c", 12.5)


И затем я рассмотрел их в окне FSI; мы увидим что-то вроде этого:

val a : int * int = (1, 2)
val b : int * string = (1, "codfather")
val c : int * string * float = (1, "c", 12.5)


Это интересно, мы можем увидеть пару вещей здесь, а именно:

  • Круглые скобки не являются частью сигнатуры типа
  • Система типов F# может правильно выводить тип на основе значений, содержащихся в самом кортеже.
  • Запятая заменяется на »*»


Так что кристально чистый кортеж выглядит так:

let a = (1,2)


Будет иметь такую сигнатуру:

int * int

Разбивка кортежей


Итак, мы увидели, как мы можем создавать кортежи, но как насчет разбивки или деконструкции их обратно в отдельные значения. Это возможно? Да, конечно. Как и прежде, давайте начнем с нескольких примеров:


let (a,b) = (1,2)
 printfn "(a,b) = (1,2), so value of 'a' should be 1, and it is =%i,\r\n 'b' should be 2, and it is =%i" a b 
// используя подстановочный знак, по сути, не создавайте ненужную привязку значения, если вы
// не заинтересован в этом
let (_,z) = (1,2)
printfn "grabbing last value from (1,2) which is = %i" z 
let (a,b :string) = (1,"cat")
printfn "grabbing (1,\"cat\") which has values = %i %s" a b 
let (a :int,b :string) = (1,"cat")
printfn "grabbing (1,\"cat\") which has values = %i %s" a b 
let (a ,b, c) = (1,"cat", 'c')
printfn "grabbing (1,\"cat\",'c') which has values = %i %s %c" a b c 
let first = fst (1, 2)
printfn "grabbing fst from (1,2) which has values = %i" first 
let second = snd (1, 2)
printfn "grabbing 2nd from (1,2) which has values = %i" second


Результаты печатаются в стандартном окне консоли, следующим образом:
image

Используя Let


Но как мы получили отдельные части? Ну, все, что вам нужно, в приведенном выше коде, но давайте рассмотрим один пример. Предположим, у нас был такой кортеж:

(1,2)


И я хотел получить значения обоих «значений» кортежа, привязанные к некоторым новым отдельным значениям, мы могли бы просто сделать это:

let (a,b) = (1,2)


Мы также можем выбрать только те значения, которые нам действительно нужны, что делается с использованием подстановочного знака для нежелательных частей. Что гарантирует отсутствие ненужного связывания значений. Вот пример:

let (_,z) = (1,2)

Использование встроенных функций кортежа


Также имеется встроенная поддержка для получения первого и второго значений из кортежа. Что можно сделать с помощью функций »fst» и »snd». Нет никакой поддержки для чего-либо, кроме 2-го элемента (это, вероятно, наиболее распространенные случаи).»fst» и »snd» можно использовать следующим образом:

let first = fst (1, 2)
let second = snd (1, 2)


Теперь я хочу обратить ваше внимание на особый случай, когда у нас может быть несоответствие с количеством значений, которые мы пытаемся взорвать на отдельные значения. Так что это будет что-то вроде примера здесь:

let (a ,b) = (1,"cat", 'c')


Вы можете видеть, что сам кортеж на самом деле содержит 3 значения, но привязка Let имеет только 2 значения, поэтому компилятор предупреждает нас об этом, как вы можете видеть на снимке экрана ниже:
image

Создание новых кортежей


Возможно, вы захотите создать новые кортежи из существующих кортежей, это достаточно просто, вот пример:

let oldOne = (1,2)
let (x,y) = oldOne
let newOne = (x+1,y+1)
printfn "original = %A, and we did this (x+1,y+1)\r\n to obtain newOne = %A" oldOne newOne


image

Сравнение кортежей


Кортежи считаются равными, только если

  • Они имеют одинаковое количество значений
  • ВСЕ значения считаются равными (очевидно, это могут быть пользовательские методы Equals или пользовательские реализации IEquatable и тому подобное)


Давайте посмотрим на какой-нибудь простой пример.

printfn "(1,2) = (3,4) =% b" ((1,2) = (3,4))
printfn "(1,2) = (1,2) =% b" ((1,2) = (1,2))
printfn "('a', 'b') = ('a', 'b') =% b" (('a', 'b') = ('a', 'b'))
printfn "('a', 'b') = ('a', 'c') =% b" (('a', 'b') = ('a', 'c'))


image

На самом деле, если ваши кортежи имеют разную длину (количество элементов) и вы пытаетесь сравнить их с помощью оператора равенства »=», вы получите предупреждение:
image

Паттерны сопоставления кортежей


Мы еще не занимались паттернами сопоставления, но позже увидим целый пост на эту тему. А пока просто знайте, что это способ снова сопоставить входные параметры. Вы можете сделать это для кортежей, что делается следующим образом:

let someFunction tup = 
    match tup with
    | 1,2 -> printfn "you passed (1,2)"
    | _,_ -> printfn "you passed some other tuple"
     
do someFunction (11,12)
do someFunction (4,5)
do someFunction (1,2)
do someFunction (13,23)


image

© Habrahabr.ru