Teste de planejamento da semântica de valor / referência de Haskell

8

Em linguagens imperativas, é trivial conceber um teste de programação do uso da linguagem de "semântica de valores" ou "semântica de referência". Pode-se fazer o seguinte e verificar o valor de a(where Vertex {one, two, three :: Integer}):

a := Vertex 3 4 5
b := a
one b   :=  6
two b   :=  8
three b := 10

No entanto, como as variáveis ​​são imutáveis ​​em linguagens funcionais, esse teste não funcionará em tais linguagens.

Sei muito pouco sobre Haskell (e programação funcional em geral), mas entendo que ele usa semântica de valor. É possível conceber um experimento de programação que distingue entre um "registro ref" e um "registro val" em Haskell?

David Chouinard
fonte
1
Na segunda frase, você quis dizer "verificar o valor de a"?
1
relevante en.wikipedia.org/wiki/…
jk.
Haskell é referencialmente transparente , [1] o que significa que 'semântica de valor' e 'semântica de referência' são equivalentes em Haskell. [1] Os geeks da linguagem de programação terão um longo debate sobre essa afirmação, mas é bastante tradicional usá-la no sentido que acabei de fazer.
Jonathan fundido

Respostas:

9

Não existe esse teste, porque, sem mutabilidade, a distinção não é significativa (como você demonstrou).

Chama de Ptharien
fonte
3
É interessante notar que algumas partes do Haskell ( IORef, MVar, etc) são mutáveis e comportam-se como referências ( hpaste.org/81192 )
Daniel Gratzer
9

Haskell não possui referências (uma referência é um objeto mutável e Haskell não possui objetos mutáveis ​​(diretamente acessíveis)). Portanto, as chamadas de função usam semântica de valores, como por padrão. Essa é de fato uma propriedade importante das linguagens funcionais puras: uma função não pode modificar seu argumento.

A semântica do valor não implica que a cópia ocorra sob o capô. Você só precisa copiar a parte de um valor que a função modifica, o que em uma linguagem pura significa que você nunca precisa copiar nada.

No entanto, essa não é a história toda. De certa forma, Haskell tem semântica de referência.

Embora não faça sentido testar se uma função modifica seu argumento (nunca o faz), você pode testar se uma função usa (parte de) seu argumento. Forneça um argumento que não termine. Se a chamada da função terminar, você sabe que a função não usou seu argumento.

let bottom = bottom
let ignore x = 1
ignore bottom

Se você avaliar bottom, ele não termina: se bottomexpande para si próprio, ad nauseam. O termo bottomnão pode ter um valor. Mas se você avaliar ignore bottom, o valor é 1. Isso mostra que chamar a função ignorenão requer o cálculo do valor de seu argumento. Nesse sentido, Haskell tem uma semântica de referência: o que uma função recebe não é um valor, mas algo que permite que esse valor seja encontrado. O termo técnico é chamar pelo nome (em vez de chamar pelo valor ).

(Mais precisamente, as implementações de Haskell usam chamada por necessidade . Na chamada por valor, o argumento de uma função é avaliado exatamente uma vez, pouco antes de chamar a função. Na chamada pelo nome, o argumento é avaliado toda vez que é usado, que pode variar de nunca a quantas vezes a função desejar. Na chamada por necessidade, o argumento é avaliado no máximo uma vez: é avaliado na primeira vez em que é usado ou nunca se não for usado.

Gilles 'SO- parar de ser mau'
fonte
2
Certamente, novamente, em um idioma puro, chamada por necessidade e chamada por nome são indistinguíveis. A chamada por necessidade simplesmente se torna uma estratégia de otimização.
Jörg W Mittag
2
@ JörgWMittag Bom ponto, esqueci de mencionar isso. (A propósito, para nitpick, a chamada por necessidade nem sempre é mais eficiente do que a chamada por nome ao operar em memória finita.)
Gilles 'SO- deixa de ser mau'
1
Sim, mas quem tem apenas memória finita? Estamos todos usando máquinas de Turing, certo? Sério: acho que é porque você tem uma certa sobrecarga de contabilidade em relação à necessidade ou não do valor, certo? Por exemplo, thunks ou algo assim?
Jörg W Mittag
3
@ JörgWMittag Mas, mesmo em uma máquina de Turing, a memória é uma limitação, pois, se você mantiver mais coisas por perto, alcançar as coisas úteis exige mais idas e vindas da fita. Em computadores reais, isso é chamado de localidade de cache ruim.
Gilles 'SO- stop be evil'
7

É impossível distinguir entre eles. O que isso significa é que o compilador é livre para optar por usar qualquer semântica que considerar adequada para um desempenho ideal.

Em particular, as linguagens funcionais são normalmente descritas como tendo semântica de valor, porque isso corresponde ao nosso modelo conceitual delas, mas geralmente são implementadas usando semântica de referência, porque é mais eficiente. (Não é necessário copiar algo que não pode ser alterado!)

Jörg W Mittag
fonte