Определение и подпись в этом синтаксисе для данных [duplicate]

Вы можете обойти это, заменив объект (и, следовательно, связать область):

def foo(a=[]):
    a = list(a)
    a.append(5)
    return a

Ужасно, но он работает.

41
задан hammar 23 November 2011 в 18:29
поделиться

2 ответа

Он определяет новый тип, синтаксис называется обобщенным типом алгебраических данных .

Он более общий, чем обычный синтаксис. Вы можете написать любое стандартное определение типа (ADT) с помощью GADT:

data E a = A a | B Integer

можно записать как:

data E a where
  A :: a -> E a
  B :: Integer -> E a

Но вы также можете ограничить то, что находится на правой стороне:

data E a where
  A :: a -> E a
  B :: Integer -> E a
  C :: Bool -> E Bool

, что невозможно с нормальным объявлением ADT.

Для получения дополнительной информации проверьте Haskell wiki или это видео .


Причина - безопасность типа. ExecutionAST t должен быть типом операторов, возвращающих t. Если вы напишете обычный ADT

data ExecutionAST result = Return result 
                         | WriteRegister M_Register Word8
                         | ReadRegister M_Register
                         | ReadMemory Word16
                         | WriteMemory Word16
                         | ...

, тогда ReadMemory 5 будет полиморфным значением типа ExecutionAST t, а не мономорфным ExecutionAST Word8, и это будет проверять тип:

x :: M_Register2
x = ...

a = Bind (ReadMemory 1) (WriteRegister2 x)

Этот оператор должен прочитать память из местоположения 1 и записать в регистр x. Однако чтение из памяти дает 8-битные слова, а для записи в x требуются 16-битные слова. Используя GADT, вы можете быть уверены, что это не скомпилируется. Ошибки времени компиляции лучше ошибок во время выполнения.

GADT также включают экзистенциальные типы . Если вы попытались написать bind таким образом:

data ExecutionAST result = ... 
                           | Bind (ExecutionAST oldres)
                                  (oldres -> ExecutionAST result)

, то он не будет компилироваться, поскольку «oldres» не находится в области видимости, вам нужно написать:

data ExecutionAST result = ...
                           | forall oldres. Bind (ExecutionAST oldres)
                                                 (oldres -> ExecutionAST result)

If вы запутались, проверьте связанное видео для более простого, родственного примера.

52
ответ дан Community 21 August 2018 в 20:54
поделиться

Обратите внимание, что также можно поставить ограничения класса:

data E a where
  A :: Eq b => b -> E b
18
ответ дан nponeccop 21 August 2018 в 20:54
поделиться
  • 1
    И что более важно, в отличие от обычных объявлений data, это фактически заставляет словарь экземпляра быть сохраненным в типе, позволяя восстановить его с помощью сопоставления с образцом, как и с экзистенциальными типами. – hammar 23 November 2011 в 19:10
  • 2
    @hammar Я не понимаю, что подразумевает ваш комментарий. Я не понимаю эту формулировку (с моей перефразировкой) ', чтобы восстановить словарь экземпляра через сопоставление шаблонов, потому что он хранится в типе'. Когда я сопоставляю шаблон, я деконструируюсь по форме структуры, и я не вижу, как это переводится в «словарь экземпляра», и почему это отличается тем, что оно хранится в типе. Что я должен читать / учиться, чтобы понять смысл этого? – Stephane Rolland 17 June 2018 в 19:06
Другие вопросы по тегам:

Похожие вопросы: