高阶程序需要环境模型吗?

问题描述 投票:0回答:1

学习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++ 永远不会有一个完整的功能映射”?

c++ functional-programming scheme higher-order-functions sicp
1个回答
0
投票

正如其他人所说,该链接非常古老。从那时起,事情发生了很大变化。

在我看来,简短的答案是,您所描述的

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。

© www.soinside.com 2019 - 2024. All rights reserved.