Eu tenho lido sobre linguagens de programação baseadas em pilha, como FORTH e Cat , e parece que, dada a sua natureza, elas podem executar apenas uma ação por vez, independentemente do seu paradigma (FORTH é imperativo enquanto Cat é funcional).
Uma linguagem imperativa modificaria a pilha, e uma linguagem puramente funcional, como Joy , retornaria uma nova pilha, mas o ponto é que apenas uma pilha é usada por vez.
Então, as linguagens de programação baseadas em pilha podem ser simultâneas? Eles poderiam obter simultaneidade usando várias pilhas ao mesmo tempo ou algo parecido?
É possível implementar a avaliação lenta em uma linguagem de programação baseada em pilha?
Corrija-me se não estiver entendendo nada sobre os idiomas e conceitos mencionados acima
fonte
Respostas:
Certo.
Já para idiomas normais, o multiencadeamento geralmente significa ter várias pilhas de "chamada". Seria completamente natural atribuir a cada thread sua própria pilha de dados. Seria fácil ter um ator, digamos, cujo corpo fosse implementado pelo código em uma linguagem baseada em pilha. O paralelismo explícito às
par
anotações do GHC deve ser razoavelmente direto. O principal problema com a execução de coisas em paralelo é que você não sabe qual será o efeito de pilha do código até executá-lo. No entanto, usando uma sintaxe do tipo Joy, pode-se imaginar[a b c] par
como executandoa b c
contra uma pilha vazia ou uma cópia da pilha e mantendo apenas o elemento mais alto da pilha (ou pressionando algum valor fictício se a pilha estiver vazia). Você pode imaginar variações. Seria mais difícil fazer ingenuamente paralelismo implícito em comparação com, digamos, uma linguagem puramente funcional, mas certamente poderia ser feito também. O código compilado de um combinador definido pelo usuário geralmente não é muito diferente do código "normal".Efeitos de pilha desconhecidos são novamente a parte complicada. Se você projetar o idioma de modo que todos os efeitos da pilha possam ser determinados estaticamente, isso não parecerá muito desafiador. Se você tem preguiça de ser explícito, também parece relativamente direto e se pareceria com as citações de Joy e
i
. Uma linguagem que se autodenomina uma linguagem concatenativa preguiçosa parece fazer uma mistura das duas abordagens acima do que posso dizer. Eu realmente não vejo como uma linguagem concatenativa implicitamente preguiçosa funcionaria diante dos efeitos de pilha dinâmica, pelo menos não de uma maneira vagamente utilizável, mas isso pode ser apenas uma falta de imaginação da minha parte.Aliás, não é incomum que os idiomas baseados em pilha tenham várias pilhas, por exemplo, a Forth possui uma pilha de dados e uma pilha de retorno na qual você também pode colocar dados arbitrários.
fonte
Eu sei um pouco sobre FORTH, então vou me limitar a isso. É uma linguagem de baixo nível, oferecendo a você como programador acesso a todos os recursos de hardware. Então você pode fazer o que quiser.
Concorrência
Para ter programas paralelos (edit: costumava dizer programas concorrentes reais), você precisa de pelo menos duas unidades de execução (CPU-s). Seria bastante trivial implementar uma palavra em FORTH dizendo, como exemplo, "execute esta palavra no processador 2 usando esses dois argumentos". A palavra alocaria as duas pilhas necessárias no processador 2 e começaria a executar a palavra. Você precisaria se restringir um pouco exatamente às construções que você pode usar nesse programa.
Se o número de programas simultâneos for maior que o número de unidades de execução, você deverá procurar programas "pseudo-paralelos". Basicamente, existem duas maneiras de fazer isso: corotinas ou multitarefa preemptiva. De qualquer forma, é possível (não fácil, mas bem descrito na literatura) como conseguir isso e o FORTH permite acessar todas as coisas de baixo nível necessárias.
Avaliação preguiçosa
Claro que você pode fazer isso no FORTH, como em praticamente qualquer linguagem de programação. Não será tão elegante ou "embutido" como em Haskell. Vou usar um exemplo muito ingênuo.
A idéia é que você defina uma "função" (usada livremente aqui) que retorne um conjunto de coisas. Um exemplo seria uma função que retorna todos os números inteiros. Você faz operações neste conjunto e, quando terminar, fornece o resultado. Como exemplo, você pode querer somar todos os números inteiros até que a soma seja maior que 1000. Uma avaliação não preguiçosa alocaria primeiro todos os números inteiros como um conjunto, o que é impossível, pois há um número infinito de números inteiros. Começaria então a trabalhar neste conjunto. Uma implementação lenta teria uma maneira de "fornecer o próximo valor no conjunto". Fazer isso realmente precisa apenas de uma variável na função "last value give".
Haskell faz as coisas dessa maneira. Obviamente, ele lida com situações mais complicadas, mas a idéia é a mesma. Ele reveste a avaliação de uma maneira que permite que você como programador se concentre no problema, não em como resolvê-lo.
fonte