简体   繁体   English

什么是数据......在Haskell中意味着什么?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM