GADT
通过提供隐式forAll
我的疑虑
::Worker MemoryBuffer int
有什么不对的,如果他们真的想要抽象缓冲区,他们可以使用一个Sum类型data Buffer=MemoryBuffer NetBuffer randombuffer
和一个类似::Worker Buffer int
data Worker x = forall b. Buffer b => Worker {buffer :: b, input :: x}
data MemoryBuffer = MemoryBuffer
memoryWorker = Worker MemoryBuffer (1 :: Int)
memoryWorker :: Worker Int
GADT通过提供隐式ForAll为使用存在类型的代码提供了清晰、更好的语法
我认为GADT语法更好是一个普遍的共识。我不会说这是因为GADT提供了隐式foralls,而是因为使用existentialquantification
扩展名启用的原始语法可能会引起混淆/误导。当然,这种语法看起来像:
data SomeType = forall a. SomeType a
或带有约束:
data SomeShowableType = forall a. Show a => SomeShowableType a
data AnyType = AnyType (forall a. a) -- need RankNTypes extension
data SomeType = SomeType (exists a. a) -- not valid GHC syntax
data SomeType' where
SomeType' :: forall a. (a -> SomeType') -- parentheses optional
data AnyType' where
AnyType' :: (forall a. a) -> AnyType'
我想这并不遥远,尽管您不必使用typeable
或data
来使用存在类型。我认为更准确的说法是,存在类型提供了一个围绕未指定类型的类型良好的“框”。框确实在某种意义上“隐藏”了类型,这允许您制作这类框的异构列表,忽略它们包含的类型。结果是,像上面的sometype'
这样的不受约束的存在式是非常没用的,而是一个受约束的类型:
data SomeShowableType' where
SomeShowableType' :: forall a. (Show a) => a -> SomeShowableType'
允许您使用模式匹配来窥视“框”内部,并使type类工具可用:
showIt :: SomeShowableType' -> String
showIt (SomeShowableType' x) = show x
注意,这适用于任何类型类,而不仅仅是typeable
或data
。
class Buffer b where
output :: String -> b -> IO ()
data Worker x = forall b. Buffer b => Worker {buffer :: b, input :: x}
data MemoryBuffer = MemoryBuffer
instance Buffer MemoryBuffer
memoryWorker = Worker MemoryBuffer (1 :: Int)
memoryWorker :: Worker Int
doWork :: Worker Int -> IO ()
doWork (Worker b x) = output (show x) b
doWorkBroken :: Worker Int -> IO ()
doWorkBroken (Worker b x) = case b of
MemoryBuffer -> error "try this" -- type error
_ -> error "try that"
data Buffer' b = Buffer' { output' :: String -> b -> IO () }
dBuffer_MemoryBuffer :: Buffer' MemoryBuffer
dBuffer_MemoryBuffer = Buffer' { output' = undefined }
存在类型具有此字典的隐藏字段:
data Worker' x = forall b. Worker' { dBuffer :: Buffer' b, buffer' :: b, input' :: x }
而对存在的worker'
值进行操作的类似doWork
的函数实现为:
doWork' :: Worker' Int -> IO ()
doWork' (Worker' dBuf b x) = output' dBuf (show x) b
对于只有一个函数的type类,字典实际上优化为newtype,因此在本例中,存在的worker
类型包括一个隐藏字段,该字段由指向缓冲区的output
函数的函数指针组成,这是DoWork
所需的唯一运行时信息。
Haskell是一种函数语言,它是严格类型化的,Haskell编译器在编译时知道整个应用程序中使用的数据类型。 1. 内置类型类 在Haskell中,每个语句都被视为数学表达式,并且此表达式的类别称为类型()。可以说是在编译时使用的表达式的数据类型。 要了解有关类型的更多信息,可以使用命令。以通用的方式可以将类型视为值,而可以将类型类视为一组相似类型的类型。在本章中,我们将学习不同的内置类型。 2
这些到底有什么区别呢?我想我理解存在类型是如何工作的,它们就像OO中的基类没有向下强制转换的方法一样。通用类型有何不同?
问题内容: 我是C ++ / Java程序员,在日常编程中碰巧使用的主要范例是OOP。在某个线程中,我读到一条评论,即Type类本质上比OOP更直观。有人可以用简单的词来解释类型类的概念,以便像我这样的OOP家伙可以理解吗? 问题答案: 首先,我总是非常怀疑这种程序结构更直观。编程是违反直觉的,并且总是会因为人们自然而然地根据特定情况而不是一般规则来思考。要更改此设置,需要培训和实践,也称为“编程
我在这段代码上得到这个错误! 错误:无法将预期类型(integer->integer->Integer)->(integer->Integer)->integer->Integer'与实际类型Integer匹配
或者我只是混淆了概念,存在类型和泛型意味着完全不同的东西。请帮我弄明白。
我希望能够使用O(1)摊销寻址与一个矢量类型,懒散地增长,根据要求的指数。 这可以通过使用:与进行配对来保持剩余部分,并使用用于分期O(1)访问的标准加倍算法来实现: 我可以只使用我的代码--但我更愿意重用别人的(比如,我还没有测试过我的代码)。 在某些包中是否存在具有这些语义的向量类型(从一个可能无限的列表中懒散地创建、O(1)分期访问)?