Языки, допускающие именованные кортежи

Мне было интересно, есть ли какие-нибудь языки, которые позволяют использовать именованные кортежи. То есть: объект с несколькими переменными разного типа и настраиваемым именем.

E.g.:

public NamedTuple<double:Speed, int:Distance> CalculateStuff(int arg1, int arg2)

var result = CalculateStuffTuple(1,2);

Console.WriteLine("Speed is: " + result.Speed.ToString())
Console.WriteLine("Distance is: " + result.Distance.ToString())

Я мог понять, как динамик может поддерживать такую ​​функцию. Статические языки, в которых я обычно плаваю (например, C #), могут использовать словарь, но это небезопасно по типу, если все элементы не относятся к одному типу. Или вы можете использовать тип Tuple, но это означает, что у вас есть фиксированные имена членов (Var1, Var2 и т. Д.).

Вы также можете написать небольшой собственный класс, но этого я бы хотел избежать.

Я мог бы представить, что язык обработки макросов мог бы написать что-то подобное для вас на статическом языке, но я не знаю такого языка.

Это вытекает из моего ответа от этого вопрос о типах возврата.


person ligos    schedule 29.09.2009    source источник
comment
Причина, по которой я хотел бы избежать использования настраиваемого класса / структуры, заключается в том, что я не люблю печатать! Не более того.   -  person ligos    schedule 30.09.2009
comment
Эта строка не должна включать Tuple. var result = CalculateStuffTuple (1,2);   -  person ctrl-alt-delor    schedule 03.02.2012


Ответы (12)


В C # у вас есть анонимные типы; они похожи, но имеют свои ограничения:

var result = new { Speed = 12.4, Distance = 8, Caption = "car 1" };

Однако их трудно использовать в качестве вызывающего, если вы не используете «приведение по примеру» (хрупкое), отражение или dynamic. Из трех последний самый аппетитный.

dynamic result = GetSomething();
Console.WriteLine(result.Speed);
Console.WriteLine(result.Distance);

В большинстве случаев было бы лучше просто использовать обычный класс, но у этого подхода есть некоторые практические применения; например, посмотрите, как они используются в ASP.NET MVC для простой и удобной передачи информации о конфигурации (в противном случае потребовался бы словарь). Это немного похоже на то, как jQuery позволяет передавать параметры как свойства объекта.

person Marc Gravell    schedule 29.09.2009
comment
Это похоже на то, что я просил (по крайней мере, в С #). - person ligos; 30.09.2009

Старый вопрос, но, я думаю, он требует лучшего решения.

Вы можете получить именованные параметры, воспользовавшись преимуществом типа Tuple, но заключив его в пользовательский именованный тип, который включает .Item1, .Item2 и т. Д. В значимые имена свойств.

Я тоже ненавижу тот факт, что кортежи имеют безымянные параметры, которые делают код нечитаемым, но не могут игнорировать время, которое экономит необходимость реализации IComparable, IStructuralEquatable и т. Д. Самостоятельно, чтобы вы могли безопасно использовать свои структуры в качестве словарного ключа, например .

Я считаю, что это очень приятный компромисс:

public class Velocity : Tuple<double, double, string>
{
    public Velocity(double Speed, double Direction, string Units) : base(Speed, Direction, Units) { }
    public double Speed { get { return this.Item1; } }
    public double Direction { get { return this.Item2; } }
    public string Units { get { return this.Item3; } }
}

Теперь вместо этой фигни:

Tuple<double, double, string> myVelocity = new Tuple<double, double, string>(10, 2.34, "cm/s");
System.Diagnostics.Debug.Print("Speed: " + myVelocity.Item1);
System.Diagnostics.Debug.Print("Direction: " + myVelocity.Item2);
System.Diagnostics.Debug.Print("Units: " + myVelocity.Item3);

Вы должны сделать это:

Velocity myVelocity2 = new Velocity(10, 2.34, "cm/s");
System.Diagnostics.Debug.Print("Speed: " + myVelocity2.Speed);
System.Diagnostics.Debug.Print("Direction: " + myVelocity2.Direction);
System.Diagnostics.Debug.Print("Units: " + myVelocity2.Units);

И вы по-прежнему пользуетесь всеми замечательными функциями кортежа, которые позволяют использовать его в качестве сложного ключа в словарях и т. Д.

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

person Alain    schedule 08.08.2012
comment
На самом деле это не так уж и плохо. За исключением того, что у меня должна быть куча маленьких классов, охватывающих Tuple<>. Но это лучше, чем повторная реализация IEquatable, IComparable и т. Д. - person ligos; 09.08.2012
comment
Не могу поверить, что никогда не думал об этом. Супер полезно. - person Timothy Shields; 25.03.2014
comment
Как раз то решение, которое я искал. Здорово :) - person Nikhil Chavan; 04.03.2015

Eiffel допускает именованные кортежи.

person James Phillips    schedule 30.09.2009

Теперь это поддерживается, начиная с C # 7.

(double speed, int distance) CalculateStuff(int arg1, int arg2)

var result = CalculateStuff(1,2);

Console.WriteLine("Speed is: " + result.speed.ToString())
Console.WriteLine("Distance is: " + result.distance.ToString())

См .: https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/

person Benoittr    schedule 14.04.2016

Я знаю;

  • Python (динамическая, строгая типизация)
  • Eiffel (статический, строковый ввод)

Оба могут использоваться в .net

И, вероятно, Lisp, вы можете делать с Lisp все что угодно.

person ctrl-alt-delor    schedule 03.02.2012

Вы имеете в виду что-то вроде collections. namedtuple в Python? Ну, Python (текущие версии 2.6 и 3.1) их поддерживает ;-). А если серьезно, я не знаю ни одного языка со статической типизацией, в котором бы они были встроены.

person Alex Martelli    schedule 29.09.2009

Я не уверен, что это именно то, что вы ищете, но в Haskell вы можете иметь запись с указанными именами и типами:

data Movement = Movement { speed :: Double, distance :: Int } deriving (Show)

main = do
    print $ Movement 3.14 100
    print Movement {distance = 5, speed = 2.1}
    print Movement {speed = 9, distance = -4}

вывод:

Movement {speed = 3.14, distance = 100}
Movement {speed = 2.1, distance = 5}
Movement {speed = 9.0, distance = -4}

Но технически это не кортеж. В Haskell есть кортежи, но, насколько мне известно, они не могут именоваться.

Это действительно не так уж и далеко от простой структуры на любом языке, производном от C. Может я что-то упустил в вопросе.

person Mark Rushakoff    schedule 29.09.2009

Что плохого в использовании структур или классов в C #?

public class SpeedDistance{
  public double Speed;
  public int Distance;
}
person Martin v. Löwis    schedule 29.09.2009
comment
Ну, публичное поле, конечно, плохая идея ... но public double Speed {get;set;} подойдет ;-p - person Marc Gravell; 29.09.2009
comment
Мне нравится, чтобы мои кортежи были неизменными. И вместо этого требуются переменные только для чтения и конструктор, который начинает становиться слишком длинным. - person ligos; 30.09.2009
comment
общедоступные поля допустимы, если и только если это все, что содержится в классе. Но кортежи также могут иметь множество других хороших свойств, которые помогают при переходе в другие библиотеки. Если они каждый раз пишутся с нуля, они не взаимодействуют. - person ctrl-alt-delor; 03.02.2012

Существует несколько таких языков. Слово для такого именованного кортежа - «запись». В языковом семействе ML есть такие записи вместе с соответствующими типами. Конкретные языки включают: SML, OCaml и, что важно, F #. Эта ссылка объясняет записи в F #: http://en.wikibooks.org/wiki/F_Sharp_Programming/Tuples_and_Records#Defining_Records

person Carsten Führmann    schedule 23.01.2013

Swift допускает именованные кортежи. Вы можете написать что-то вроде:

let interval = (start: 0, end: 10)
let start = interval.start

По сути, это анонимные структуры.

person Mihai Damian    schedule 04.08.2015

Спасибо, Ален. Вот как я воспользовался твоей подсказкой.

Загрузчик динамических изображений для карусели

<div id="owl" class="owl-carousel owl-theme">
    @foreach (var image in Model.Sketches)
    {
        <div class="item" >
            <a href="@image.SketchHref" id="[email protected]" target="_blank" >
                <img id="[email protected]" class="lazyOwl" style="border:1px solid #d1c7c7;outline : 0;max-height:350px;max-width:400px;" 
                    title="click for full size" alt="@image.SketchName" data-src="@image.SketchHref" /></a>
                    <div style="text-align:left;height:auto;vertical-align:bottom;padding:2px;font-size:1em;color:#DF3A01;">Sketch @image.SketchNumber of @Model.Sketches.Count()</div>
        </div>
    }
    </div>

А для C #

    public List<Sketches> Sketches 
    {
        get
        {
            List<Sketches> hrefs = new List<Sketches>();

/ * имя изображения соответствует примеру расположения папки: 1234101005_001.Gif будет равно "c: \ images \ 1234 \ 10 \ 1005_BLD \" * /

            var sketchFolder = Regex.Replace(some_image, @"(\d{4})(\d{2})(\d{4})", @"c:\Sketches\$1\$2\$3\_BLD");
            var sketchHref = Regex.Replace(some_image, @"(\d{4})(\d{2})(\d{4})", @"/sketches/$1/$2/$3/_BLD");
            Int16 i = 0;

            if (System.IO.Directory.Exists(sketchFolder))
            {
                List<string> gifs = GetGifs(sketchFolder);

                gifs.ForEach(delegate(String gif)
                {
                    string s = sketchHref + "/" + gif;
                    string f = sketchFolder + "/" + gif;

                    if (System.IO.File.Exists(f))
                    {
                        Sketches sketch = new Sketches(s, (++i).ToString(), gif);
                        hrefs.Add(sketch);
                    }
                    else // gif does not exist
                    {
                        Sketches sketch = new Sketches("placeholder.png", (++i).ToString(), gif);
                        hrefs.Add(sketch);
                    }
                });
            }
            else // folder does not exist
            {
                Sketches sketch = new Sketches("placeholder.png", (++i).ToString(), "");
                hrefs.Add(sketch);
            }
            return hrefs;
        }
    }

public class Sketches : Tuple<string, string, string>
{
    public Sketches(string SketchHref, string SketchNumber, string SketchName) : base(SketchHref, SketchNumber, SketchName) { }
    public string SketchHref { get { return this.Item1; } }
    public string SketchNumber { get { return this.Item2; } }
    public string SketchName { get { return this.Item3; } }
}
person Gregory Bologna    schedule 24.06.2015

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

Я не знаю ни одного статически типизированного языка, который бы поддерживал бы это, но C # определенно не поддерживает.

person Andrew Hare    schedule 29.09.2009