简体   繁体   English

类型级编程在运行时意味着什么?

[英]What does type level programming mean at runtime?

I am very new to Haskell, so sorry if this is a basic question, or a question founded on shaky understanding 我对Haskell很新,如果这是一个基本问题,或者基于不稳定理解的问题,那就很抱歉

Type level programming is a fascinating idea to me. 类型级编程对我来说是一个很有意思的想法。 I think I get the basic premise, but I feel like there is another side to it that is fuzzy to me. 我认为我得到了基本的前提,但我觉得还有另一面对我来说是模糊的。 I get that the idea is to bring logic and computation into the compiletime instead of runtime, using types. 我认为这个想法是使用类型将逻辑和计算带入编译时而不是运行时。 This way you turn what is normally runtime logic/state/data into static logic, eg the size of collections. 通过这种方式,您可以将通常的运行时逻辑/状态/数据转换为静态逻辑,例如集合的大小。

So I get that for example you can have type level natural numbers, and do type level arithmetic on those natural numbers, and all this calculation and type safety is going on at compile time. 所以我得到了例如你可以有类型级自然数,并对这些自然数进行类型级算术,所有这些计算和类型安全性在编译时进行。

But what does such arithmetic imply at runtime? 但这种算术在运行时意味着什么呢? Especially since Haskell has full type erasure. 特别是因为Haskell具有完全类型的擦除。 So for example 所以举个例子

  • If I concatenate two type level lists, then does the type level safety imply something about the behavior or performance of that concatenation at runtime? 如果我连接两个类型级别列表,那么类型级别安全性是否意味着在运行时该连接的行为或性能? Or does the type level programming aspect only have meaning at compile time, when the programmer is grappling the code and putting things together? 或者类型级编程方面只在编译时有意义,当程序员正在努力解决代码并将事物放在一起时?
  • Or if I have two type level numbers, and then multiply them, what does that mean at runtime? 或者,如果我有两个类型级别编号,然后将它们相乘,那么这在运行时意味着什么? If these operations on large numbers are slow at compile time, are they instantaneous at runtime? 如果这些大数字操作在编译时很慢,那么它们是否在运行时瞬间完成?
  • Or if we implemented type level RSA and then use it, what does that even mean at runtime? 或者,如果我们实现了类型级别的RSA然后使用它,那在运行时甚至意味着什么呢?

Is it purely a compiletime safety/coherence tool? 它纯粹是一个编译时安全/一致性工具吗? or does type level programming buy us anything for the runtime too? 或类型级编程是否也为运行时购买任何东西? Is the logic and arithmetic 'paid for at compile time' or merely 'assured at compile time' (if that even makes sense)? 逻辑和算术是“在编译时支付”还是仅仅“在编译时保证”(如果这有意义的话)?

As you rightly say, Haskell [without weird extensions] has full type erasure. 正如你所说,Haskell [没有奇怪的扩展]有完整的类型擦除。 So that means anything computed purely at the type level is erased at runtime. 这意味着纯粹在类型级别计算的任何内容都会在运行时被擦除。

However, to do useful stuff, you connect the type-level stuff with your value-level stuff to provide useful properties. 但是,要做有用的东西,可以将类型级别的东西与值级别的东西连接起来,以提供有用的属性。

Suppose, for example, you want to write a function that takes a pair of lists, treats them as mathematical vectors, and performs a vector dot-product with them. 例如,假设您要编写一个带有一对列表的函数,将它们视为数学向量,并使用它们执行向量点积。 Now the dot-product is only defined on pairs of vectors of the same size . 现在,点积只定义在相同大小的矢量对 So if the size of the vectors doesn't match, you can't return a sensible answer. 因此,如果向量的大小不匹配,则无法返回合理的答案。

Without type-level programming, your options are: 没有类型级编程,您的选择是:

  • Require that the caller always supplies vectors of the same dimension, and cheerfully return gibberish if that requirement is not met. 要求调用者始终提供相同维度的向量,并且如果不满足该要求,则高兴地返回乱码。 (Ie, ignore the problem.) (即,忽略这个问题。)
  • Perform an explicit check at run-time, and throw an exception or return Nothing or similar if the dimension don't match. 在运行时执行显式检查,如果维度不匹配,则抛出异常或返回Nothing或类似内容。

With type-level programming, you can make it so that if the dimensions don't match, the code does not compile! 使用类型级编程,您可以使它如果尺寸不匹配, 代码就不会编译! So that means at run-time you don't need to care about mismatched dimension, because... well, if your code is running, then the dimension cannot be mismatched. 因此,这意味着在运行时您不需要关心不匹配的维度,因为......好吧,如果您的代码正在运行,那么维度就不会不匹配。

The types have all been erased by this point, but you are still guaranteed that your code cannot crash / return gibberish, because the compiler has checked that that cannot happen. 这些类型已被删除,但您仍然保证您的代码不会崩溃/返回乱码,因为编译器已经检查过这种情况不会发生。

It's really the same as the ordinary checks the compiler does to make sure you don't try to multiply an integer by a string or something. 它与编译器执行的普通检查完全相同,以确保您不会尝试将整数乘以字符串或其他内容。 The types are all erased before runtime, and yet the code does not crash. 这些类型都在运行时被擦除,但代码不会崩溃。


Of course, to do a dot-product, we merely have to check that two numbers are equal . 当然,要做一个点积,我们只需要检查两个数字是否相等 We don't need any arithmetic yet. 我们还不需要任何算术 But it should be clear that to check whether the dimensions of our vectors match, we need to know the dimensions of our vectors. 但是应该清楚的是,为了检查我们的向量的维度是否匹配,我们需要知道向量的维数。 And that means that any operations that change the dimension of our vectors needs to do compile-time calculations, so the compiler can know the result size and check it satisfies the requirements. 这意味着任何改变向量维度的操作都需要进行编译时计算,因此编译器可以知道结果大小并检查它是否满足要求。

You can also do more elaborate stuff. 你也可以做更精细的东西。 Somewhere I saw a library that lets you define a client/server communications protocol, but because it encodes the protocol into ludicrously complicated type signatures [which the compiler automatically infers], it can statically prove that the client and server implement exactly the same protocol (ie, no bugs with the server not handling one of the messages the client can send). 在某个地方,我看到了一个允许您定义客户端/服务器通信协议的库,但由于它将协议编码为编译器自动推断的非常复杂的类型签名,它可以静态地证明客户端和服务器实现完全相同的协议(即,没有错误,服务器没有处理客户端可以发送的消息之一)。 The types get erased at runtime, but we still know the wire protocol can't go wrong. 这些类型在运行时被擦除,但我们仍然知道有线协议不会出错。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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