Idiomas com uma distinção clara entre sub-rotinas que são puramente funcionais, mutantes, de mudança de estado etc.?

8

Ultimamente, fico cada vez mais frustrado que, nas linguagens de programação mais modernas com as quais trabalhei (C / C ++, C #, F #, Ruby, Python, JS e mais), há muito pouco, se houver, suporte à linguagem para determinar o que uma sub-rotina realmente funciona.

Considere o seguinte pseudocódigo simples:

var x = DoSomethingWith(y);

Como determino o que a chamada para DoSomethingWith (y) realmente fará? Será que vai mutação y , ou vai retornar uma cópia de y ? Depende do estado global ou local, ou depende apenas de y ? Mudará o estado global ou local? Como o fechamento afeta o resultado da chamada?

Em todos os idiomas que encontrei, quase nenhuma dessas perguntas pode ser respondida apenas com a assinatura da sub-rotina, e quase nunca há suporte em tempo de compilação ou em tempo de execução. Normalmente, a única maneira é confiar no autor da API e torcer para que a documentação e / ou convenções de nomenclatura revelem o que a sub-rotina realmente fará.

Minha pergunta é a seguinte: Existe alguma linguagem hoje que faz distinções simbólicas entre esses tipos de cenários e coloca restrições em tempo de compilação em qual código você pode realmente escrever?

(É claro que há algum suporte para isso na maioria das linguagens modernas, como diferentes níveis de escopo e fechamento, a separação entre código estático e de instância, funções lambda etc.). Mas, com muita frequência, elas parecem entrar em conflito entre si. Por exemplo, uma função lambda normalmente é puramente funcional e simplesmente retorna um valor com base nos parâmetros de entrada ou altera os parâmetros de entrada de alguma maneira, mas geralmente é possível acessar variáveis ​​estáticas de uma função lambda, que por sua vez pode dar acesso a variáveis ​​de instância e depois tudo se separa.)

Christian Palmstierna
fonte
1
Observe que "puramente funcional" é ambíguo. Você provavelmente quer dizer "puro" (livre de efeitos colaterais); "funcional" implica um paradigma de programação que trata funções como objetos de primeira classe e permite funções de ordem superior. Essas funções não precisam necessariamente ser puras, e a maioria das linguagens de programação funcionais permite funções impuras.
tdammers
Isso soa como uma importante distinção semântica a ser feita. O que quero dizer com funcional é no sentido matemático, ou seja, que a rotina depende apenas dos dados de entrada e não lê nem grava em nenhum outro dado no programa. "Função pura" é um termo mais correto para descrever isso?
Christian Palmstierna

Respostas:

10

Sim, você quer olhar para Haskell. Faz exatamente o que você quer. Todas as funções são puras por padrão e só podem mudar de estado usando Mônadas. Também Haskell tem fortes garantias estáticas sobre todos os tipos de coisas http://learnyouahaskell.com/

Zachary K
fonte
Ah! Ouvi muitas coisas boas sobre Haskell, mas não consegui investigar profundamente. Talvez ele vai caber minha conta :)
Christian Palmstierna
Parece ser onde um monte de coisas interessantes estão acontecendo
Zachary K
5
Mônadas não podem mudar de estado mais do que outros tipos de dados; eles estão vinculados pelas mesmas restrições de pureza que o restante do idioma. Afinal, não há nada de especial neles, além de algum açúcar sintático. O que eles podem fazer é fornecer uma abstração conveniente sobre o código que acumula estado através de chamadas de função encadeadas ou recursivas e, quando compiladas no tempo de execução, esse código se resume a um código imperativo semelhante ao código monádico. Ainda é uma abstração e o código ainda é 100% puro.
tdammers
4
Além disso, as funções não são puras por padrão, são puras, ponto final. Haskell não pode expressar funções impuras.
tdammers
3
@CPX: Existem pelo menos três frameworks web fortes para o setor para Haskell (Yesod, Happstack e Snap), e uma abundância de bibliotecas para praticamente todas as tarefas que você menciona (embora não tenha certeza sobre o SOAP); a qualidade média do código no ecossistema Haskell tende a ser excelente. O maior problema que posso prever é encontrar programadores suficientes para suportar isso durante um período de manutenção mais longo.
tdammers
6

C e C ++ têm suporte muito limitado para pelo menos parte do problema por meio da constpalavra - chave; embora isso por si só não controle a pureza, ele pode ser usado (especialmente em C ++) para informar ao compilador que uma estrutura de dados específica não deve ser modificada por meio de um determinado ponteiro. Alguns compiladores (por exemplo, gcc) também fornecem um atributo 'puro' como uma extensão de idioma para impor totalmente a pureza. (Veja esta pergunta para detalhes).

A linguagem de programação D tem suporte para declarar explicitamente a pureza das funções, e os compiladores verificarão e reforçarão a pureza (ou seja, tentar chamar uma função não pura de dentro de uma função pura gera um erro do compilador).

Haskell é completamente puro, ou seja, a própria linguagem não pode expressar funções impuras, e não há conceito de "rotina". Tudo o que não pode ser resolvido usando apenas funções puras é terceirizado para o tempo de execução (impuro); um programa com efeitos colaterais é implementado construindo (usando construções exclusivamente puras) uma estrutura de dados lenta que descreve o comportamento do programa e entregando-a ao tempo de execução. A comunidade Haskell está experimentando ativamente um zoológico inteiro de linguagens de programação, algumas delas puras, outras com pureza explícita.

Pode haver mais, mas é com esses que eu estou familiarizado.

tdammers
fonte
gcc faz apoio explícito declarações de pureza como uma extensão como assim
Useless
As funções de membro const do C ++ controlam a pureza, se suas classes não tiverem funções de membro não const. Todos os dados se tornam constantes e, em seguida, tudo é puramente funcional.
tp1
@ TP1: Não é bem assim. Uma função membro const pode facilmente produzir efeitos colaterais chamando métodos estáticos não-const de outras classes, instanciando outras classes ou simplesmente chamando funções livres ou modificando variáveis ​​globais. Só funciona se você bloquear toda a sua base de código em all-const, incluindo todas as bibliotecas que você usa (mesmo STL).
tdammers
@ Tdammers: O bloqueio all-const não é muito ruim, pois os dados podem ser inicializados com valores diferentes pelos parâmetros do construtor. Mas exige que todos os seus dados estejam localizados dentro de suas classes e não em variáveis ​​globais.
tp1
@ tp1: Também é muito impraticável, porque reduz o número de bibliotecas que você pode usar com segurança para praticamente zero.
tdammers
1

Felix tem três categorias, parece:

  1. funções

    There is a rule for functions: 
    
    A function introduced by a fun binder is not allowed to have any side effects.
    
    The compiler does not enforce this rule, but it does take advantage of it when
    optimising your code. 
    
  2. procedimentos

    Procedures do not return a value, and may and generally should have side-effects.
    
  3. geradores

    A generator is a function that may have side effects.
    
yakiv
fonte
Isso soa como uma linguagem que tenta fazer exatamente o que eu estou procurando. É lamentável que as funções não sejam impostas pelo compilador (depois de alguns anos trabalhando profissionalmente, desenvolvi uma desconfiança instintiva para as bibliotecas de outros programadores ;-)). Além disso, uma vez que é tão novo, eu posso mexer com ele, mas não parece um candidato ao desenvolvimento comercial / profissional :(
Christian Palmstierna
1
@ChristianPalmstierna: Acabei de tropeçar nessa pergunta de anos atrás. Infelizmente, como tantas propriedades interessantes, decidir se uma função é pura é equivalente a resolver o problema de parada. Observe que isso não significa necessariamente que você não pode fazê-lo, apenas significa que existem infinitamente muitas funções puras cuja pureza o compilador não pode provar e, portanto, deve rejeitar como impuro, mesmo que não o sejam. (Isso não é diferente de typechecking estática, embora Normalmente, existem infinitamente muitos programas que são seguros, mas não podem ser comprovadas tipo seguro não nos impede de digitação...)
Jörg W Mittag