2013-02-20 15 views
37

Понятно, что любой n-кортеж может быть представлен связкой вложенных 2-кортежей. Так почему же они не то же самое в Haskell? Разве это что-то сломает?Почему (a, b, c, d) не сахар для (a, (b, (c, (d,()))))?

Выполнение этих эквивалентов типов значительно упростит функции записи на кортежах. Например, вместо определения zip, zip2, zip3 и т. Д. Вы можете определить только одну функцию zip, которая будет работать для всех кортежей.

Конечно, вы можете работа с вложенными 2-кортежами, но это некрасиво и нет никакого канонического пути для выполнения вложенности (т.е. должны ли мы гнездо влево или вправо?).

+0

http://stackoverflow.com/questions/14621559/n-ary-tuples-vs-pairs –

ответ

35

Тип (a,b,c,d) имеет различный профиль производительности от (a,(b,(c,(d,())))). Как правило, индексирование в n-кортеж принимает O(1), а индексирование в «hlist» из n вложенных кортежей принимает O(n).

Тем не менее, вы должны проверить классические работы Олега на HLists. Использование HLists требует обширного и несколько отрывочного использования программирования уровня. Многие люди считают это неприемлемым, и он не был доступен в раннем Haskell. Возможно, лучший способ, чтобы представить HList сегодня с GADTs и DataKinds

data HList ls where 
    Nil :: HList '[] 
    Cons :: x -> HList xs -> HList (x ': xs) 

Это даст каноническое вложение, и позволяет писать функции, которые работают для всех экземпляров этого типа. Вы можете реализовать свой многопользовательский способ zipWith, используя те же методы, что и в printf. Более интересная головоломка состоит в том, чтобы сгенерировать соответствующие линзы для этого типа (подсказка: использовать типы типов naturals и типы семейств для индексации).

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

EDIT: чем больше я думаю об этом, тем более склонным я должен что-то взломать, когда у меня есть время. Повторяющаяся проблема копирования Андреаса Росберга упоминается, вероятно, может быть устранена с использованием потокового синтеза или аналогичных методов.

+0

Я видел работу Олега, и именно это заставило меня начать эту основную идею. Синтаксис для его библиотеки (и всех вариантов, которые я видел) просто ужасно использовать на практике. Кроме того, я не понимал, что вложенные кортежи используют хит производительности O (n). Невозможно ли выполнить компилятор для устранения O (1)? –

+0

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

+0

@MikeIzbicki Я говорил о производительности во время исполнения.В принципе, его можно было бы, вероятно, вставлять в кортежи большую часть времени, но в настоящее время у нас нет такого компилятора. Обратите внимание, что поскольку шаблоны на C++ можно использовать «unboxed», реализация кортежей C++ может быть полностью общей по своему усмотрению. GHC не позволяет вам отбрасывать полиморфные поля, поэтому мы не можем этого сделать (следовательно, решение представляет собой библиотеку, использующую массивы небезопасной принудительной внутренней). –

23

Основная проблема с этим в Haskell заключается в том, что вложенный кортеж допускает дополнительные значения из-за лени. Например, тип (a,(b,()) населен всеми (x,_|_) или (x,(y,_|_)), что не относится к плоским кортежам. Существование этих значений не только семантически неудобно, но и затрудняет оптимизацию кортежей.

На строгом языке, однако, ваше предложение действительно является возможностью. Но он все еще вводит ошибку производительности: реализации все равно хотели бы сгладить кортежи. Следовательно, в тех случаях, когда вы фактически строите или деконструируете их индуктивно, им придется много повторять копирование. Когда вы используете действительно большие кортежи, это может быть проблемой.

+3

Что делать, если мы делаем строго вложенные кортежи, изоморфные их сплюснутым аналогам, то есть что-то вроде: '(a,! (b,! (c,!()))) ~ (a, b, c)'? Кроме того, не удалось ли выполнить это копирование во время компиляции вместо времени выполнения? –

+1

@MikeIzbicki, AFAICT, в Haskell нет такой вещи, как тип '' (a,! (...)) ''. Вы можете только аннотировать параметры конструкторов типов данных как строгие. Что касается копирования, конечно, нет необходимости, когда вы записываете литерал кортежа, но когда вы строите или деконструируете один * индуктивно *, т. Е. Путем рекурсии по его длине, я не вижу способа избежать этого. –

+2

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

Смежные вопросы