Ao aprender SICP, 6.001 lec15 tem:
Um bom entendimento do modelo de ambiente me diz por que (na minha humilde opinião) C++ nunca terá um mapa totalmente funcional , filtro e procedimentos fold-right/fold-left que sejam tão convenientes quanto os do Scheme
O SICP implementamap
:
(define (map proc items)
(if (null? items)
nil
(cons (proc (car items))
(map proc (cdr items)))))
Aqui, cada chamada recursiva map
criará um novo ambiente para cada lista de argumentos (proc items)
, para que eles possam ser independentes (semelhante a for proc
e cons
etc).
Mas na minha opinião, em C++ o código acima pode ser feito com as mesmas ideias baseadas em stack . Então a independência ainda é mantida.
Por que a aula diz "C++ nunca terá um mapa totalmente funcional " devido ao "modelo de ambiente"?
Como outros disseram, esse link é muito antigo. As coisas mudaram muito desde então.
A resposta curta, na minha opinião, é que o que
map
você descreve já existe em C++ (C++20) e é chamado destd::ranges::views::transform
, que pode ser usado assimque "corresponde" a
no Esquema.
Eu citei corresponde porque não sei exatamente como as coisas acontecem em tempo de execução para o código Scheme acima. Eu sei que isso
std::ranges::views::transform
é preguiçoso, ou seja, nenhum trabalho é realmente executado (no sentido def
não ser invocado de forma alguma) ao escrever a linha C++ acima. Somente ao acessar os valores dew
via API range, esses valores serão realmente computados, portantof
serão chamados.Mas eu sei que funciona, em termos de preguiça, como o código Haskell correspondente (que se assemelha muito ao código Scheme):
Além disso, o conceito de "mapeamento" não é tão restrito quanto o implícito no trecho de código e na afirmação de que
porque essa
map
é uma implementação ad-hoc demap
for lists. Então é tão "funcional" quanto um programa que lida explicitamente com listas o tempo todo sem nunca definir abstrações de alto nível.... O que é bom no Scheme porque tudo é uma lista, verdade, mas você ainda teria que redefinir
map_assocmap
para executar uma função nos valores de um "mapa associativo" (que ainda seria uma lista, no final das contas, no Scheme, por exemplo(define myassocmap '((k1 v1) (k2 v2) (k3 v3)))
, masmap_assocmap
não seriamap
, porque(map_assocmap f myassocmap)
teria que chamarf
apenas emv1
,v2
,v3
.)Mas a questão é que o conceito de
map
ping é mais geral e diz respeito aos Functores , como são conhecidos na teoria das categorias e na programação funcional .E C++ oferece algo nessa direção. Por exemplo, você pode mapear um opcional, em C++: dado a
std::optional<T>
e uma função do tipoU(T)
, faz sentido executar essa função no valor dentro do opcional, se houver um, obtendo assim um opcional não vazio do tipostd::optional<U>
, ou retornar um vaziostd::optional<U>
(std::nullopt
) se o opcional original estiver vazio. Isso, em C++, é a função membrostd::optional<T>::transform
.Isto corresponderia ao seguinte, no Esquema
assumindo que alguém tenha definido a API
nullOpt?
+'nullOpt
+makeOpt
+unwrapOpt
.