Estou tentando visualizar alguns sistemas físicos automáticos simples (coisas como pêndulo, braços de robô, etc.) em Haskell. Muitas vezes, esses sistemas podem ser descritos por equações como
df/dt = c*f(t) + u(t)
onde u(t)
representa algum tipo de 'controle inteligente'. Esses sistemas parecem se encaixar muito bem no paradigma da Programação Reativa Funcional.
Então eu peguei o livro "The Haskell School of Expression" de Paul Hudak, e descobri que a linguagem de domínio específico "FAL" (para Functional Animation Language) apresentada lá realmente funciona muito bem para meus sistemas de brinquedo simples (embora algumas funções, notavelmente integrate
, parecia ser um pouco preguiçoso para um uso eficiente, mas facilmente corrigível).
Minha pergunta é: qual é a alternativa mais madura, atualizada, bem mantida e ajustada para o desempenho para aplicações mais avançadas ou mesmo práticas hoje?
Esta página wiki lista várias opções para Haskell, mas não tenho certeza sobre os seguintes aspectos:
O status de "reativo", o projeto de Conal Eliott que é (como eu o entendo) um dos inventores deste paradigma de programação, parece um pouco obsoleto. Eu amo seu código, mas talvez eu devesse tentar outras alternativas mais atualizadas? Qual é a principal diferença entre eles, em termos de sintaxe / desempenho / estabilidade de tempo de execução?
Para citar uma pesquisa em 2011, Seção 6, " ... as implementações de FRP ainda não são eficientes ou previsíveis o suficiente em desempenho para serem usadas com eficácia em domínios que exigem garantias de latência ... ". Embora a pesquisa sugira algumas possíveis otimizações interessantes, dado o fato de que o FRP existe há mais de 15 anos, tenho a impressão de que esse problema de desempenho pode ser algo muito ou mesmo inerentemente difícil de resolver pelo menos em alguns anos. Isso é verdade?
O mesmo autor da pesquisa fala sobre "vazamentos de tempo" em seu blog . O problema é exclusivo do FRP ou algo que geralmente enfrentamos ao programar em uma linguagem pura e não estrita? Você já achou muito difícil estabilizar um sistema baseado em FRP ao longo do tempo, se não apresentar desempenho suficiente?
Este ainda é um projeto de nível de pesquisa? As pessoas, como engenheiros de fábrica, engenheiros de robótica, engenheiros financeiros, etc., estão realmente os usando (em qualquer linguagem que atenda às suas necessidades)?
Embora eu pessoalmente prefira uma implementação de Haskell, estou aberto a outras sugestões. Por exemplo, seria particularmente divertido ter uma implementação Erlang --- seria muito fácil ter um processo de servidor inteligente, adaptável e de autoaprendizagem!
Embora já existam algumas respostas boas, tentarei responder às suas perguntas específicas.
reativo não é utilizável para projetos sérios, devido a problemas de vazamento de tempo. (ver # 3). A biblioteca atual com o design mais semelhante é reativa-banana, que foi desenvolvida tendo reativo como inspiração, e em discussão com Conal Elliott.
Embora o próprio Haskell seja impróprio para aplicativos de tempo real de disco rígido, é possível usar o Haskell para aplicativos de tempo real de software em alguns casos. Não estou familiarizado com as pesquisas atuais, mas não acredito que este seja um problema intransponível. Suspeito que sistemas como o Yampa ou sistemas de geração de código como Atom são possivelmente a melhor abordagem para resolver isso.
Um "vazamento de tempo" é um problema específico do FRP comutável. O vazamento ocorre quando um sistema é incapaz de liberar objetos antigos porque pode precisar deles se uma troca ocorrer em algum momento no futuro. Além de um vazamento de memória (que pode ser bastante grave), outra consequência é que, quando a troca ocorre, o sistema deve pausar enquanto a cadeia de objetos antigos é percorrida para gerar o estado atual.
Bibliotecas frp não comutáveis, como Yampa e versões mais antigas de banana reativa, não sofrem com vazamentos de tempo. Bibliotecas frp comutáveis geralmente empregam um de dois esquemas: ou têm uma "mônada de criação" especial na qual os valores de FRP são criados ou usam um parâmetro de tipo "envelhecimento" para limitar os contextos nos quais as trocas podem ocorrer. elerea (e possivelmente netwire?) usa o primeiro, enquanto a banana reativa recente e a toranja usam o último.
Por "frp comutável", quero dizer aquele que implementa a função de Conal
switcher :: Behavior a -> Event (Behavior a) -> Behavior a
, ou semântica idêntica. Isso significa que a forma da rede pode mudar dinamicamente à medida que é executada.Isso realmente não contradiz a afirmação de @ertes sobre interfaces monádicas: acontece que fornecer uma
Monad
instância para umEvent
torna possível o vazamento de tempo, e com qualquer uma das abordagens acima não é mais possível definir as instâncias Monad equivalentes.Finalmente, embora ainda haja muito trabalho a ser feito com o FRP, acho que algumas das plataformas mais novas (banana reativa, elerea, netwire) são estáveis e maduras o suficiente para que você possa construir um código confiável a partir delas. Mas talvez você precise gastar muito tempo aprendendo os meandros para entender como obter um bom desempenho.
fonte
Vou listar alguns itens no espaço Mono e .Net e um no espaço Haskell que encontrei não muito tempo atrás. Vou começar com Haskell.
Elm - link
Sua descrição de acordo com seu site:
Ele tem sua própria variante de FRP . Brincando com seus exemplos, parece bem maduro.
Extensões reativas - link
Descrição da primeira página:
As extensões reativas vêm do MSFT e implementam muitos operadores excelentes que simplificam o tratamento de eventos. isso foi código aberto apenas alguns dias atrás. É muito maduro e usado na produção; na minha opinião, teria sido uma API melhor para as APIs do Windows 8 do que a biblioteca TPL fornece; porque os observáveis podem ser quentes e frios e repetidos / mesclados etc., enquanto as tarefas sempre representam cálculos quentes ou concluídos que estão em execução, com falha ou concluídos.
Escrevi código do lado do servidor usando Rx para assincronização, mas devo admitir que escrever funcionalmente em C # pode ser um pouco chato. F # tem alguns wrappers, mas tem sido difícil rastrear o desenvolvimento da API, porque o grupo é relativamente fechado e não é promovido pela MSFT como outros projetos.
Seu código-fonte aberto veio com o código-fonte aberto de seu compilador IL-to-JS, portanto, provavelmente poderia funcionar bem com JavaScript ou Elm.
Você provavelmente poderia vincular F # / C # / JS / Haskell muito bem usando um agente de mensagens, como RabbitMQ e SocksJS.
Bling UI Toolkit - link
Descrição da primeira página:
Artigo LtU de cortesia .
Eu testei isso, mas não trabalhei com isso para um projeto de cliente. Parece incrível, tem uma ótima sobrecarga de operadores C # que formam as ligações entre os valores. Ele usa propriedades de dependência em WPF / SL / (WinRT) como fontes de eventos. Suas animações 3D funcionam bem em hardware razoável. Eu usaria isso se acabasse em um projeto que precisasse de visualizações; provavelmente portando-o para o Windows 8.
ReactiveUI - link
Paul Betts, anteriormente na MSFT, agora no Github, escreveu essa estrutura. Trabalhei com ele extensivamente e gosto do modelo. É mais desacoplado do que o Blink (por sua natureza de usar Rx e suas abstrações) - tornando mais fácil testar a unidade de código usando-o. O cliente github git para Windows está escrito nisso.
Comentários
O modelo reativo tem desempenho suficiente para a maioria dos aplicativos que exigem desempenho. Se você está pensando em tempo real difícil, aposto que a maioria das linguagens GC tem problemas. Rx, ReactiveUI criam alguma quantidade de pequenos objetos que precisam ser GCed, porque é assim que as assinaturas são criadas / descartadas e os valores intermediários progridem na "mônada" reativa de retornos de chamada. Em geral em .Net eu prefiro a programação reativa à programação baseada em tarefas porque os retornos de chamada são estáticos (conhecidos no tempo de compilação, sem alocação) enquanto as tarefas são alocadas dinamicamente (não conhecido, todas as chamadas precisam de uma instância, lixo criado) - e lambdas compilam em classes geradas por compilador.
Obviamente, C # e F # são avaliados estritamente, portanto, o vazamento de tempo não é um problema aqui. O mesmo para JS. Pode ser um problema com observáveis reproduzíveis ou em cache.
fonte
u(t)
e as simulaçõesf(t)
. É esse o caso das implementações F #?