scala - 运行时避免 asInstanceOf
问题描述
这是尝试在运行时组合函数的设计的简化版本。因此,pipelineS
在运行时(以 json 或其他形式)并遍历执行它。此外,我们知道运行时输入将是一个有效的组合(函数输入/输出类型匹配)。
我想定义具有类型信息的函数并避免asInstanceOF
.
我看到的一个部分解决方案是Here,但它非常复杂,很难扩展到不同大小的输入参数。
abstract class Func extends Product {
val meta:FuncMeta
}
case class FuncMeta(name:String, outType:String, inTypes:List[String])
case class Fun0(meta:FuncMeta, run:() => Any) extends Func
case class Fun1(meta:FuncMeta, run:Any => Any) extends Func
case class Fun2(meta:FuncMeta, run:(Any, Any) => Any) extends Func
val literal2 = Fun0(FuncMeta("literal2", "int", List.empty), () => 2)
val literal10 = Fun0(FuncMeta("literal10", "int", List.empty), () => 10)
val twice = Fun1(FuncMeta("twice", "int", "int" :: Nil) ,(a:Any) => a.asInstanceOf[Int] * 2)
val larger = Fun2(FuncMeta("larger", "bool", "int" :: "int" :: Nil) ,(a:Any, b:Any) => a.asInstanceOf[Int] > b.asInstanceOf[Int])
val add = Fun2(FuncMeta("add", "int", "int" :: Nil), (a:Any, b:Any) => a.asInstanceOf[Int] + b.asInstanceOf[Int])
//a Map[String, Func] for runtime access and retrieve of functions
//Basically this is the way the Functions are stored
val funcs = List(literal2, literal10, twice, larger, add).map(x => x.meta.name -> x).toMap
def traverse(tree: Treee[Func]):Any = {
val t = tree.t
val kids = tree.kids
val rs = kids.map(k => traverse(k))
t match {
case Fun0(meta, run) => run()
case Fun1(meta, run) => run(rs.head)
case Fun2(meta, run) => run(rs(0), rs(1))
}
}
//RUNTIME information
//can be a userinput Json that gets converted to the following by accessing the funcs Map
val pipelineS = Treee[Func](
funcs("larger"),
List(
Treee(funcs("literal10")),
Treee(funcs("literal2"))
)
)
println(traverse(pipelineS))
解决方案
好吧,您可以创建一个像这样的类型化编码:
sealed trait Term {
type T
def run(): T
}
object Term {
type Aux[_T] = Term { type T = _T }
}
final case class Lit[A] (value: A) extends Term {
override final type T = A
override final def run(): T = value
}
final case class Tuple[A, B](a: Term.Aux[A], b: Term.Aux[B]) extends Term {
override final type T = (A, B)
override final def run(): T = (a.run(), b.run())
}
final case class Fun[I, O](input: Term.Aux[I])(f: I => O) extends Term {
override final type T = O
override final def run(): T = f(input.run())
}
可以这样使用:
val expr: Term = Fun(Tuple(Lit(2), Fun(Lit(3))(_ * 5))) {
case (a, b) => a + b
}
expr.run()
// res: Term.T = 17
问题是如何从您的用户输入中创建这样的表达式。
推荐阅读
- javascript - 多个反应 useState 调用给出未定义的属性
- node.js - AdonisJs - 找不到模块
- c# - 使用 fluentmigrator 尝试捕获未按预期工作
- mysql - 如何在mysql中用小写名称替换所有表名?
- azure-pipelines - 在 Azure Devops MS 代理上的 Python SDK 中使用 Azure CLI 2.30.0 凭据时,“无法从服务主体的本地缓存中检索凭据”
- python - 带格式的简单 Python 任务
- nginx - Nginx 没有从 www 重定向到 https
- sql - 连接文本变量并保留双引号
- ios - SwiftUI 中的网格布局
- node.js - 无法在 node.js 中使用 mailgun 发送电子邮件