Нет, вы не можете. Во-первых, есть небольшая терминологическая путаница: у вас есть списки, а не массивы (which Haskell also has), хотя точка стоит в любом случае. Итак, как и все вещи Haskell, вы должны задать себе вопрос: Какой тип aList = [aList, 1]
быть?
Рассмотрим более простой случай aList = [aList]
. Мы знаем, что aList
должен быть список что-то, поэтому aList :: [α]
для некоего типа α
. Что такое α
? Как тип элементов списка, мы знаем, что α
должен быть типом aList
; то есть α ~ [α]
, где ~
представляет собой равенство типов. Итак, α ~ [α] ~ [[α]] ~ [[[α]]] ~ ⋯ ~ [⋯[α]⋯] ~ ⋯
. Это, действительно, бесконечный тип, и Хаскелл запрещает такие вещи.
В случае значения aList = [aList, 1]
, у вас также есть ограничение, что 1 :: α
, но все то, что позволяет нам сделать вывод, что должно быть Num α
ограничение (Num α => [⋯[α]⋯]
), что ничего не изменится.
Очевидные следующие три вопроса:
- Почему Haskell списки содержат только один тип элемента?
- Почему Haskell запрещает бесконечные типы?
- Что я могу сделать по этому поводу?
Давайте рассмотрим их в порядке.
Номер один: Почему списки Haskell содержат только один тип элемента? Это из-за системы типа Хаскелла. Предположим, у вас есть список значений разных типов: [False,1,2.0,'c']
. Каков тип функции someElement n = [False,1,2.0,'c'] !! n
? Нет никого, потому что вы не могли знать, какой тип вы вернетесь. Так что же вы можете сделать с этой ценностью? В конце концов, вы ничего не знаете об этом!
Номер два: Почему Haskell запрещает бесконечные типы? Проблема с бесконечными типами заключается в том, что они не добавляют много возможностей (вы всегда можете обернуть их новым типом, см. Ниже), и они делают некоторые проверки подлинности ошибок. Например, in the question "Why does this Haskell code produce the ‘infinite type’ error?", несуществование бесконечных типов исключало ошибку с ошибкой intersperse
(и даже без явной сигнатуры типа).
Номер три: Что я могу сделать по этому поводу? Если вы хотите подделать бесконечный тип в Haskell, вы должны использовать рекурсивный тип данных . Тип данных не позволяет типу иметь поистине бесконечное расширение, и очевидность избегает случайных ошибок, упомянутых выше. Таким образом, мы можем определить NewType для бесконечно вложенного списка выглядит следующим образом:
Prelude> newtype INL a = MkINL [INL a] deriving Show
Prelude> let aList = MkINL [aList]
Prelude> :t aList
aList :: INL a
Prelude> aList
MkINL [MkINL [MkINL [MkINL ^CInterrupted.
Это у нас наш бесконечно вложенный список, что мы хотели-печать это никогда не собирается прекращать, но ни один из типов были бесконечна. (INL a
является изоморфными к [INL a]
, но это не равное к нему Если вам интересно об этом, разница между isorecursive types (what Haskell has) and equirecursive types (which allow infinite types)..)
Но обратите внимание, что этот тип не очень полезно; единственными содержащимися в нем списками являются либо бесконечно вложенные вещи, как aList
, либо различные вложенные коллекции пустого списка. Там нет никакого способа, чтобы получить базовый случай значения типа a
в одном из списков:
Prelude> MkINL [()]
<interactive>:15:8:
Couldn't match expected type `INL a0' with actual type `()'
In the expression:()
In the first argument of `MkINL', namely `[()]'
In the expression: MkINL [()]
Так что список вы хотите, это произвольно вложенный список. 99 Haskell Problems имеет вопрос о них, который требует определения нового типа данных:
data NestedList a = Elem a | List [NestedList a]
Каждый элемент NestedList a
является либо простым значением типа a
, или список более NestedList a
с. (Это то же самое, произвольно-ветвящегося дерева, которое сохраняет данные только в листьях.) Тогда у вас есть
Prelude> data NestedList a = Elem a | List [NestedList a] deriving Show
Prelude> let aList = List [aList, Elem 1]
Prelude> :t aList
aList :: NestedList Integer
Prelude> aList
List [List [List [List ^CInterrupted.
Вы должны определить свои собственные функции просмотра теперь, и обратите внимание, что, вероятно, тип NestedList a -> Int -> Maybe (NestedList a)
-the Maybe
предназначен для работы с целыми числами вне диапазона, но важная часть состоит в том, что он не может просто вернуть a
. В конце концов, aList ! 0
не является целым числом!
что вы имеете в виду под «размещая массив внутри сам'? только 2d-массивы? в списке Haskell есть структура данных по умолчанию, и вы можете иметь список, содержащий другие списки (типа [[a]]) – jev
@jev anArray рекурсивно определен, поэтому 'anArray !! 0 !! 1' будет эквивалентен' aArray !! 0 !! 0 !! 1' или 'anArray !! 0 !! 0 !! 0 !! 1'. Рекурсивно определенный массив не совпадает с 2-мерным массивом. –
Эта общая идея называется [«связывание узла»] (http://www.haskell.org/haskellwiki/Tying_the_Knot) в Haskell. – leftaroundabout