在学习SICP时,6.001 lec15具有:
对环境模型的良好理解告诉我为什么(恕我直言)C++ 永远不会有功能齐全的 map、 filter 和 fold-right/fold-left 程序,像 Scheme 一样方便
SICP实现map
:
(define (map proc items)
(if (null? items)
nil
(cons (proc (car items))
(map proc (cdr items)))))
这里每个递归调用map
都会为每个参数列表创建一个新的环境(proc items)
,因此它们可以独立(类似于proc
和cons
等)。
但我认为,在 C++ 中,上述代码可以基于堆栈以相同的思想完成。因此仍然保持独立性。
为什么 lec 会说由于“环境模型”, “C++ 永远不会拥有功能齐全的地图”?
正如其他人所说,该链接非常古老。从那时起情况发生了很大变化。
我认为,简短的回答是,
map
你描述的已经存在于 C++(C++20)中,它被称为std::ranges::views::transform
,可以像这样使用“对应”于
在 Scheme 中。
我引用了对应部分,因为我不知道上面的 Scheme 代码在运行时究竟发生了什么。我知道这是偷懒的,即在编写上面的 C++ 行时实际上没有执行任何工作(在某种意义上根本没有调用)。只有当通过 range API访问值时,这些值才会被实际计算,因此才会被调用。
std::ranges::views::transform
f
w
f
但我知道它在懒惰方面是有效的,就像相应的 Haskell 代码(与 Scheme 代码非常相似)一样:
此外,“映射”的概念甚至不像代码片段和声明中暗示的那样狭窄
因为这
map
是列表的临时实现map
。因此,它就像一个始终明确处理列表而从未定义高级抽象的程序一样“实用”。...这在 Scheme 中是可以的,因为一切都是列表,没错,但你仍然必须重新定义
map_assocmap
以在“关联映射”的值上运行一个函数(在 Scheme 中,它最终仍然是一个列表,例如(define myassocmap '((k1 v1) (k2 v2) (k3 v3)))
,但map_assocmap
不是map
,因为(map_assocmap f myassocmap)
必须在、、f
上调用唯一的。)v1
v2
v3
但重点是
map
ping 的概念更加通用,它属于函子(Functor),就像范畴论和函数编程中所知道的那样。C++ 确实提供了一些这方面的功能。例如,在 C++ 中,您可以映射一个可选项:给定一个
std::optional<T>
和类型为 的函数U(T)
,则对可选项中的值执行该函数(如果有)是有意义的,从而获得类型为 的非空可选项std::optional<U>
,或者如果原始可选项为空,则返回一个空的std::optional<U>
(std::nullopt
)。在 C++ 中,这就是成员函数std::optional<T>::transform
。在 Scheme 中,这对应于以下内容
假设已经定义了+++
nullOpt?
API 。'nullOpt
makeOpt
unwrapOpt