c++ - 如何使用类型级函数动态创建静态类型?

标签 c++ typescript scala haskell ocaml

在 TypeScript 中,有 类型级允许基于给定的创建新类型的函数 文字 类型/规范(参见 Mapped TypesConditional Types 等)。

例如,这里有这样一个函数,假设由 lib 作者提供:

type FromSpec<S> = { 
  [K in keyof S]: S[K] extends "foo" ? ExampleType : never 
};

它的目的是,给定一个规范 S以字符串键和任意文字的映射的形式,它以映射的形式创建一个具有相同键集和值转换的新类型。如果 a 值是文字 "foo"那么它变成了类型 ExampleType , 否则通过将其转换为底部类型来拒绝该值 never .

然后,最终用户可以使用此功能按照上述说明创建新类型:

type Example = FromSpec<{some_key: "foo", another_key: "bar"}>
//           = {some_key: ExampleType, another_key: never} 

值得注意的是,lib 作者不知道给定的最终用户可能想要的确切类型,因此为他提供了一个函数来创建他需要的类型。另一方面,最终用户只要符合函数的能力,就可以创建无限的新类型集。

你可以玩转这个简单的例子,here .

问题是这种“动态”如何在其他类型语言(例如 ReasonML/OCaml、Scala、Haskell)中表达。或者作为最终用户如何创建新类型,在编译时 ,通过使用由 lib 作者提供的类型级函数(正如人们通常在运行时使用值级函数所做的那样)?

重要的是要注意,问题不在于哪种语言更好等等。而是关于找到最直接的和显式 表达这种能力的方式。在这里我们看到了一个 TypeScript 的例子,但是还有没有 天然 以任何其他语言的方式?

最佳答案

鉴于 Scala 是标记语言之一,这里是 Dotty(又名 Scala 3)中的解决方案。对此持保留态度,因为 Dotty 仍在开发中。用 Dotty 0.24.0-RC1 版本测试,这里是 a Scastie that proves this actually compiles .

Scala 没有与 TypeScript 相同的用于操作记录的内置类型机制。不要害怕,我们可以自己动手!

import deriving._

// A field is literally just a tuple of field name and value
type Field[K, V] = (K, V)

// This just helps type-inference infer singleton types in the right places
def field[K <: String with Singleton, V <: Singleton](
  label: K,
  value: V
): Field[K, V] = label -> value

// Here is an example of some records
val myRec1 = ()
val myRec2 = field("key1", "foo") *: field("key2", "foo") *: () 
val myRec3 =
  field("key1", 1) *: field("key2", "foo") *: field("key3", "hello world") *: ()

然后,FromSpec可以使用 match-type 来实现. never TypeScript 中的类型被称为 Nothing在 Scala/Dotty 中。

// Could be defined to be useful - `trait` is just an easy way to bring a new type in 
trait ExampleType
val exampleValue = new ExampleType {}

type FromSpec[S <: Tuple] <: Tuple = S match {
  case Field[k, "foo"] *: rest => Field[k, ExampleType] *: FromSpec[rest]
  case Field[k, v] *: rest => Field[k, Nothing] *: FromSpec[rest]
  case Unit => Unit
}

最后,让我们使用 FromSpec :

def myRec1Spec: FromSpec[myRec1.type] = ()
def myRec2Spec: FromSpec[myRec2.type] =
  field("key1", exampleValue) *: field("key2", exampleValue) *: () 
def myRec3Spec: FromSpec[myRec3.type] = ??? // no non-diverging implementation

关于c++ - 如何使用类型级函数动态创建静态类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62248481/

相关文章:

c++ - 无法为二维数组对象成员赋值

c++ - 段错误(核心已转储)- vector

c++ - c++ 中 map_instance[key] 与 map_instance.find(key) 的区别

scala - 将json正文添加到http4s请求

android - 用jar文件加速dex进程,可能吗?

json - 使用circe状态转换JSON

c++ - 重载运算符时二进制表达式的无效操作数

Angular ,回调不会改变变量

Angular 2 : error TS2307: Cannot find module 'socket.io-client'

javascript - typescript 中的 Angular2 过滤器