我正在通过Make a Lisp来学习 Rust。
\n作为评估器步骤的一部分,我需要创建一个将字符串(或其他内容)映射到函数的关联结构。在我更熟悉的语言(Ruby、Clojure)中,我会简单地在哈希图中定义匿名函数,例如
\n{ :+ (fn [a b] (+ a b))\n :- (fn [a b] (- a b)) } ; etc\nRun Code Online (Sandbox Code Playgroud)\n在 Rust 中,由于类型错误,这是不可能的expected closure, found a different closure。
let repl_env = HashMap::new();\n\nrepl_env.insert("+", |a, b| a + b);\nrepl_env.insert("-", |a, b| a - b); // expected closure, found a different closure\nRun Code Online (Sandbox Code Playgroud)\n我想这里发生的事情是
\nHashMap编译器正在推断as中的类型<String, WhateverTypeTheFirstClosureIs>no two closures, even if identical, have the same type?我可以向参数添加类型,从而使返回类型可推断,但这并没有帮助 \xe2\x80\x94 我认为我需要以某种方式注释闭包本身的类型?我在文档中找不到执行此操作的方法。该错误表明装箱,但将闭包包裹起来并Box::new没有帮助。(我以前从未Box编辑过)。
我还想知道 a 中的 Rust 闭包是否HashMap适合在这里使用。我应该使用enum某种吗?(当我向我的 lisp 添加用户定义的函数时,我想稍后动态添加东西,所以我假设不是)。
这里实际上不需要闭包,因为您没有关闭任何东西,您只是使用匿名静态函数。
这意味着您只需将匿名函数转换为函数指针即可正常工作,例如
let mut repl_env: HashMap<_, fn(i32, i32) -> i32> = HashMap::new();
repl_env.insert("+", |a, b| a + b);
repl_env.insert("-", |a, b| a - b);
Run Code Online (Sandbox Code Playgroud)
如果您确实需要闭包,那么您必须使用某种动态调度(因为每个闭包都是完全不同的类型),通常类似于“Box”,例如
let mut repl_env: HashMap<_, Box<dyn Fn(i32, i32) -> i32>> = HashMap::new();
repl_env.insert("+", Box::new(|a, b| a + b));
repl_env.insert("-", Box::new(|a, b| a - b));
Run Code Online (Sandbox Code Playgroud)
后一个版本就是错误消息所讨论的内容:对闭包进行装箱[并且](在本例中)使其成为特征对象。
我应该使用某种枚举吗?
使用枚举可能是一个好主意,因为最终您将拥有具有不同签名的函数:在这里您仅限于 的签名(i32, i32) -> i32。尽管您可以选择更新通用签名,例如(Values) -> Value并在内部执行调度/类型检查/...
当我将用户定义的函数添加到我的 lisp 中时,我想稍后动态添加一些东西,所以我假设不是。
如果您想保持“本机”函数和“用户”函数之间的区别,您始终可以有一个变体,它将评估用户函数的结果存储在枚举中。无论如何,您都需要一种方法来区分它们,因为最终评估者不会以相同的方式称呼它们。
尽管我认为通常的方法是使所有可见函数统一为“用户区”,并根据内置函数来实现这些函数(可以在语法上进行区分,或特殊形式,甚至由编译器进行模式匹配,并且可能会也可能不会)可供用户空间访问)。
我不知道 Lisps 通常是如何从根本上做到这一点的,但是例如你可以让解释器评估以下术语:
(+ a b)
Run Code Online (Sandbox Code Playgroud)
并检查这+是已知/标准函数以及a已知b兼容类型,然后在内部执行操作而不实际调用任何内容。
有趣的是,您可以提供一个正确定义的+函数,如下所示
(+ a b)
Run Code Online (Sandbox Code Playgroud)
乍一看这看起来很无意义,因为它应该对自身进行递归,但是解释器可以对内部节点进行模式匹配,因此这可以作为高阶函数的钩子。
例如,许多 Smalltalks 就是这样做的。非文字发送将落入蹦床方法中,然后该方法将无形地弹入内置操作中。
| 归档时间: |
|
| 查看次数: |
1150 次 |
| 最近记录: |