Для чего нужны одинаковые и нулевые элементы?

В С# 7.0 введены кортежи значений, а также поддержка некоторых языков. Они также добавили поддержку одиночных и нулевых кортежей; однако я не мог найти ни одного сценария, когда они могут быть полезны.

По ValueTuple.Create перегрузки я могу создавать любые ValueTuple.Create кортежей, но синтаксис С# 7.0 допускает, по крайней мере, два элемента:

Microsoft (R) Roslyn C# Compiler version 2.8.3.62923
Loading context from 'CSharpInteractive.rsp'.
Type "#help" for more information.
> ValueTuple.Create()
[()]
> ValueTuple.Create(1)
[(1)]
> ValueTuple.Create(1, "x")
[(1, x)]

Синтаксисом кортежа:

> var t2 = (1, 2);
> var t1 = (1); // t1 is now int (of course)
> ValueTuple<int> t1 = (1);
(1,23): error CS0029: Cannot implicitly convert type 'int' to 'ValueTuple<int>'
> ValueTuple<int> t1 = new ValueTuple<int>(1);
> t1
[(1)]

Я думаю, что я нашел поток, где была запрошена эта функция, но ни один из примеров кода не действителен на С# сейчас и не мог найти ссылок на запланированные функции С# 8.0, даже не на шаблоны рекурсивного кортежа.

В упомянутой теме указаны языки функционального программирования нитей запроса. Может быть, какой-либо функциональный язык, который использует их сейчас? Я не эксперт F #, но его ссылка на tuple не упоминает использование одиночных и нулевых кортежей.

Поэтому вопросы TL; DR:

  • Являются ли одиночные и нулевые кортежи элементов используемыми на любом (возможно, функциональном) языке.NET? Я имею в виду не Tuple.Create или конструкторами, а поддержкой родного языка.
  • Планируется ли их использовать в будущей версии С#?
  • Или они там для "на всякий случай", для будущей совместимости?

Ответ 1

Что хорошего в 0-кортеже?

Набор из 2-х кортежей или 3-кортежей представляет собой группу связанных предметов. (Точки в 2D-пространстве, RGB-значения цвета и т.д.). 1-кортеж не очень полезен, поскольку его можно легко заменить одним int.

0-кортеж кажется еще более бесполезным, поскольку в нем нет абсолютно ничего. Тем не менее он обладает свойствами, которые делают его очень полезным в функциональных языках, таких как F #. Например, тип 0-кортежа имеет ровно одно значение, обычно представленное как (). Все 0-кортежи имеют это значение, поэтому он по существу однотонный. В большинстве функциональных языков программирования, включая F #, это называется типом unit.

Функции, возвращающие void в С#, возвращают тип unit в F #:

let printResult = printfn "Hello"

Запустите это в интерактивном интерпретаторе F #, и вы увидите:

val printResult : unit = ()

Это означает, что значение printResult имеет тип unit и имеет значение () (пустой кортеж, одно и единственное значение типа unit).

Функции также могут принимать тип unit в качестве параметра. В F # функции могут выглядеть так, как будто они не принимают никаких параметров. Но на самом деле они берут единственный параметр unit типа. Эта функция:

let doMath() = 2 + 4

на самом деле эквивалентно:

let doMath () = 2 + 4

То есть, функция, которая принимает один параметр unit типа и возвращает значение int 6. Если вы посмотрите на подпись типа, которую интерпретирует интерактивный интерпретатор F # при определении этой функции, вы увидите:

val doMath : unit -> int

Тот факт, что все функции будут принимать по крайней мере один параметр и возвращать значение, даже если это значение иногда является "бесполезным" значением like (), означает, что композиция функций намного проще в F #, чем на языках, на которых нет тип unit. Но это более продвинутый предмет, о котором мы поговорим позже. Пока просто помните, что когда вы видите unit в сигнатуре функции или () в параметрах функции, то тип 0-кортежа, который служит в качестве способа сказать "Эта функция принимает или возвращает значения без значимых значений".

Ответ 2

Я не могу придумать пример использования для одного элемента кортежа. РЕДАКТИРОВАТЬ. Как указывалось, ссылка ссылается на один элемент кортежей как способ для обозначения возвращаемых параметров, что действительно полезно, хотя это, скорее всего, С#.

Нулевой элемент кортежа находится в функциональных языках, также известных как единица. Это своего рода эквивалент void в С#, который не имеет некоторых (большинства?) Функциональных языков.

Разница в том, что() является фактическим значением, которое вы можете делать с такими же, как удержать список, совпадение с шаблоном и т.д. Функциональные языки нуждаются в этом, потому что функция должна что-то возвращать, и если вы хотите вернуть "ничего", что вам нужно сделать это явно, возвращая(). Вы также можете написать функцию, которая принимает блок как параметр, что в основном означает его значение с задержкой выполнения, скорее всего, с побочными эффектами:

let x = getFromDb() // will read DB
stream.Flush() // will change state

Ответ 3

Нет поддержки для o-кортежа (nople) 1-кортежа (одно) в С#.

Однако в библиотеке базового класса (BCL) для согласованности и на случай, если кто-то в будущем найдет для нее использование, есть ValueTuple и ValueTuple<T>. Например, язык, который имеет конструкции для 0-кортежей и 1-кортежей.

ValueTuple имеет некоторую добавленную стоимость. Из документации:

Структура ValueTuple представляет собой кортеж, который не имеет элементов. Это полезно в первую очередь для его статических методов, которые позволяют создавать и сравнивать экземпляры типов кортежей значений. Его вспомогательные методы позволяют создавать экземпляры значений без необходимости явно указывать тип каждого компонента кортежа значения. Вызывая его статические методы Create, вы можете создавать кортежи значений, имеющие от нуля до восьми компонентов. Для наборов значений с более чем восемью компонентами вы должны вызвать конструктор ValueTuple.

Ответ 4

На данный момент ValueTuple'1 используется только в представлениях длинных кортежей, хотя для 1-кортежей не существует синтаксиса кортежей С#: ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8>> является базовым типом для 8-кортежей.

Что касается 0-кортежей и ValueTuple'0, мы предполагаем, что они могут появиться в будущих сценариях (возможно, некоторые рекурсивные шаблоны, если я правильно помню).