Вы можете обойти это, заменив объект (и, следовательно, связать область):
def foo(a=[]):
a = list(a)
a.append(5)
return a
Ужасно, но он работает.
Он определяет новый тип, синтаксис называется обобщенным типом алгебраических данных .
Он более общий, чем обычный синтаксис. Вы можете написать любое стандартное определение типа (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 вы запутались, проверьте связанное видео для более простого, родственного примера.
Обратите внимание, что также можно поставить ограничения класса:
data E a where
A :: Eq b => b -> E b
data
, это фактически заставляет словарь экземпляра быть сохраненным в типе, позволяя восстановить его с помощью сопоставления с образцом, как и с экзистенциальными типами.
– hammar
23 November 2011 в 19:10