学习SICP时,6.001lec15有:
对环境模型的充分理解告诉我为什么(恕我直言)C++永远不会有像Scheme一样方便的功能齐全的映射、过滤器和右折叠/左折叠程序
SICP 实施
map
:
(define (map proc items)
(if (null? items)
nil
(cons (proc (car items))
(map proc (cdr items)))))
这里每个递归调用
map
都会为每个参数列表(proc items)
创建一个新的env,因此它们可以是独立的(类似于
proc
和cons
等)。
但在我看来,在C++中,上面的代码可以基于stack用相同的想法来完成。所以仍然保持独立。
为什么 lec 说“由于“环境模型”,C++ 永远不会有一个完整的功能映射”?
正如其他人所说,该链接非常古老。从那时起,事情发生了很大变化。
在我看来,简短的答案是,您所描述的
map
已经存在于 C++ (C++20) 中,它被称为 std::ranges::views::transform
,其中
可以这样用
auto w = v | transform(f);
“对应”于
(define w (map f v))
在方案中。
我引用了对应内容,因为我不确切知道上面的方案代码如何在运行时发生事情。我知道 std::ranges::views::transform
是惰性的,即在编写上面的 C++ 行时,实际上没有执行任何工作(从根本不调用
f
的意义上来说)。只有当通过范围 API 访问
w
的值时,这些值才会被实际计算,因此
f
才会被调用。但我知道它在懒惰方面是有效的,就像相应的 Haskell 代码一样:
let w = map f v
此外,“映射”的概念甚至不像代码片段和声明所暗示的那么狭窄
C++ 永远不会有功能齐全的地图因为
that map
是
map
对于列表的临时实现。...这在Scheme中是可以的,因为一切都是一个列表,这是真的,但是你仍然需要重新定义
map_assocmap
来对“关联映射”的值运行一个函数(它仍然是一个列表,在在计划中,例如
(define myassocmap '((k1 v1) (k2 v2) (k3 v3)))
,但
map_assocmap
不会是
map
,因为
(map_assocmap f myassocmap)
必须仅在
f
、
v1
、
v2
上调用
v3
.)但重点是
map
ping 的概念更通用,它属于函子,如类别理论和函数式编程中所知。 C++ 确实在这个方向上提供了一些东西。例如,您
可以在C++中映射一个可选值:给定一个std::optional<T>
和一个类型为
U(T)
的函数,如果有一个可选值,则可以对可选值内的值执行该函数,从而获得一个
std::optional<U>
类型的非空可选,或者如果原始可选为空,则返回空
std::optional<U>
(
std::nullopt
)。在 C++ 中,这是成员函数
std::optional<T>::transform
。
这将对应于方案中的以下内容
(define (mapOpt f opt)
(if (nullOpt? opt)
'nullOpt
(f (makeOpt (unwrapOpt opt)))))
假设已经定义了 nullOpt?
+
'nullOpt
+
makeOpt
+
unwrapOpt
API。