Почему я не могу создать большие кортежи в Haskell? Почему существует предел размера кортежа?
Prelude> (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)
<interactive>:1:0:
No instance for (Show
(t,
t1,
t2,
...
t23))
arising from a use of `print' at <interactive>:1:0-48
Possible fix:
add an instance declaration for
(Show
(t,
t1,
t2,
...
t23))
In a stmt of a 'do' expression: print it
Кортежи могут быть произвольной длины*, но Show, а также Eq, Ord, Read, Bounded и т.д. инстанцируются только до 15 кортежей. Из отчета Haskell 98 §6.1.4:
Не существует верхней границы на размер кортежа, но некоторые реализации Haskell могут ограничивать размер кортежей и ограничивать экземпляры, связанные с большими кортежами. Однако каждая реализация Haskell должна поддерживать кортежи размером до 15, вместе с экземплярами для Eq, Ord, Bounded, Read и Show. Прелюдия и библиотеки определяют функции кортежей, такие как zip, для кортежей размером до 7.
Как говорили другие, если вам нужен кортеж размером 24, вам следует использовать лучшую структуру данных.
Edit: * начиная с GHC 6.12.2, максимальный размер кортежа составляет 62:
Prelude> :t (1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8)
<interactive>:1:0:
A 64-tuple is too large for GHC
(max size is 62)
Workaround: use nested tuples or define a data type
Вы можете создавать более крупные кортежи, но вам придется определять их самостоятельно. Во-вторых, у вас нет экземпляра Show, поэтому вам также придется написать экземпляр для этого.
В целом, это плохая идея использовать большие кортежи, когда лучше использовать более умный тип данных, например, вектор. Мы препятствуем такому использованию, ограничивая размер, предоставляемый по умолчанию.
Многие причитали хаскеллерам, что кортежи не являются композиционными. Таким образом, любой класс типов должен быть определен для каждого размера кортежа. Я думаю, что в отчете говорится, что экземпляры нужно определять только до 10 элементов или что-то в этом роде.
На практике я никогда не использую больше тройки. Если вы используете кортежи для выполнения какой-то логики на уровне типов, создайте композиционный вариант и используйте его вместо этого. Например:
infixr 9 :*
data a :* b = a :* !b
Тогда тип пятерки Ints будет следующим:
Int :* Int :* Int :* Int :* Int :* ()
Единица ()
в конце важна для логики уровня типа, а также для правильности строгости (вы бы не стали хотите, чтобы последний элемент был строгим, а все остальные - ленивыми).
Обратите внимание на взрыв в объявлении. Это означает, что правая часть кортежа является строгой, так что тип, подобный приведенному выше 5ple, может быть сведен к единому фрагменту памяти, чтобы последующие элементы не были более дорогими для доступа, чем более ранние.