什么数据…在Haskell意味着什么?
我在omegagb的devlog上看到了这个片段:
data ExecutionAST result where Return :: result -> ExecutionAST result Bind :: (ExecutionAST oldres) -> (oldres -> ExecutionAST result) -> ExecutionAST result WriteRegister :: M_Register -> Word8 -> ExecutionAST () ReadRegister :: M_Register -> ExecutionAST Word8 WriteRegister2 :: M_Register2 -> Word16 -> ExecutionAST () ReadRegister2 :: M_Register2 -> ExecutionAST Word16 WriteMemory :: Word16 -> Word8 -> ExecutionAST () ReadMemory :: Word16 -> ExecutionAST Word8
data ... where
是什么意思? 我以为关键字data
是用来定义一个新的types。
它定义了一个新的types,语法被称为广义代数数据types 。
它比正常的语法更普遍。 您可以使用GADT编写任何正常的types定义(ADT):
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或此video 。
原因是types安全。 ExecutionAST t
应该是返回t
的语句types。 如果你写一个正常的ADT
data ExecutionAST result = Return result | WriteRegister M_Register Word8 | ReadRegister M_Register | ReadMemory Word16 | WriteMemory Word16 | ...
那么ReadMemory 5
将是typesExecutionAST t
一个多态值,而不是单形的ExecutionAST Word8
,并且这将会inputcheck:
x :: M_Register2 x = ... a = Bind (ReadMemory 1) (WriteRegister2 x)
该语句应该从位置1读取内存并写入寄存器x
。 但是,从内存中读取给出8位字,写入x
需要16位字。 通过使用GADT,你可以肯定这不会被编译。 编译时错误比运行时错误好。
GADT还包括存在types 。 如果你试图用这种方式写入绑定:
data ExecutionAST result = ... | Bind (ExecutionAST oldres) (oldres -> ExecutionAST result)
那么它将不会编译,因为“oldres”不在范围内,你必须写:
data ExecutionAST result = ... | forall oldres. Bind (ExecutionAST oldres) (oldres -> ExecutionAST result)
如果您感到困惑,请查看链接的video以获取更简单的相关示例。
请注意,也可以把类限制:
data E a where A :: Eq b => b -> E b