[英]What does data … where mean in Haskell?
I saw this snippet at the devlog of omegagb : 我在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
What does the data ... where
mean? data ... where
是什么data ... where
意思是什么? I thought the keyword data
is used to define a new type. 我认为关键字
data
用于定义新类型。
It defines a new type, the syntax is called generalized algebraic data type . 它定义了一种新类型,语法称为广义代数数据类型 。
It is more general than the normal syntax. 它比普通语法更通用。 You can write any normal type definition (ADT) using GADTs:
您可以使用GADT编写任何普通类型定义(ADT):
data E a = A a | B Integer
can be written as: 可以写成:
data E a where
A :: a -> E a
B :: Integer -> E a
But you can also restrict what is on right hand side: 但你也可以限制右边的内容:
data E a where
A :: a -> E a
B :: Integer -> E a
C :: Bool -> E Bool
which is not possible with a normal ADT declaration. 这是正常的ADT声明无法实现的。
For more, check Haskell wiki or this video . 有关更多信息,请查看Haskell wiki或此视频 。
The reason is type safety. 原因是类型安全。
ExecutionAST t
is supposed to be type of statements returning t
. ExecutionAST t
应该是返回t
的语句类型。 If you write a normal ADT 如果你写一个正常的ADT
data ExecutionAST result = Return result
| WriteRegister M_Register Word8
| ReadRegister M_Register
| ReadMemory Word16
| WriteMemory Word16
| ...
then ReadMemory 5
will be a polymorphic value of type ExecutionAST t
, instead of monomorphic ExecutionAST Word8
, and this will type check: 然后
ReadMemory 5
将是ExecutionAST t
类型的多态值,而不是单态ExecutionAST Word8
,这将键入check:
x :: M_Register2
x = ...
a = Bind (ReadMemory 1) (WriteRegister2 x)
That statement should read memory from location 1 and write to register x
. 该语句应从位置1读取内存并写入寄存器
x
。 However, reading from memory gives 8-bit words, and writing to x
requires 16-bit words. 但是,从存储器读取产生8位字,写入
x
需要16位字。 By using a GADT, you can be sure this won't compile. 通过使用GADT,您可以确定这不会编译。 Compile-time errors are better than run-time errors.
编译时错误比运行时错误更好。
GADTs also include existential types . GADT还包括存在类型 。 If you tried to write bind this way:
如果您尝试以这种方式编写绑定:
data ExecutionAST result = ...
| Bind (ExecutionAST oldres)
(oldres -> ExecutionAST result)
then it won't compile since "oldres" is not in scope, you have to write: 然后它不会编译,因为“oldres”不在范围内,你必须写:
data ExecutionAST result = ...
| forall oldres. Bind (ExecutionAST oldres)
(oldres -> ExecutionAST result)
If you are confused, check the linked video for simpler, related example. 如果您感到困惑,请查看链接的视频以获取更简单的相关示例。
Note that it is also possible to put class constraints: 请注意,也可以放置类约束:
data E a where
A :: Eq b => b -> E b
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.