Recentemente, peguei o bug do FP (tentando aprender Haskell) e fiquei realmente impressionado com o que vi até agora (funções de primeira classe, avaliação preguiçosa e todas as outras vantagens). Ainda não sou especialista, mas já comecei a achar mais fácil raciocinar "funcionalmente" do que imperativamente para algoritmos básicos (e estou tendo problemas para voltar ao que preciso).
A única área em que o atual FP parece falhar é a programação da GUI. A abordagem Haskell parece ser apenas agrupar kits de ferramentas da GUI imperativos (como GTK + ou wxWidgets) e usar blocos "do" para simular um estilo imperativo. Eu não usei o F #, mas meu entendimento é que ele faz algo semelhante usando OOP com classes .NET. Obviamente, há uma boa razão para isso - a programação da GUI atual é sobre E / S e efeitos colaterais; portanto, a programação puramente funcional não é possível com a maioria das estruturas atuais.
Minha pergunta é: é possível ter uma abordagem funcional para a programação da GUI? Estou tendo problemas para imaginar como isso seria na prática. Alguém sabe de estruturas, experimentais ou não, que tentam esse tipo de coisa (ou mesmo estruturas projetadas desde o início para uma linguagem funcional)? Ou a solução é usar apenas uma abordagem híbrida, com OOP para as partes da GUI e FP para a lógica? (Estou apenas perguntando por curiosidade - adoraria pensar que o FP é "o futuro", mas a programação da GUI parece um buraco muito grande para preencher.)
Respostas:
Essa não é realmente a "abordagem Haskell" - é assim que você se liga aos kits de ferramentas da GUI imperativos mais diretamente - através de uma interface imperativa. Por acaso, Haskell tem ligações bastante proeminentes.
Existem várias abordagens puramente funcionais / declarativas moderadamente maduras ou mais experimentais para GUIs, principalmente em Haskell, e principalmente usando programação reativa funcional.
Alguns exemplos são:
Para aqueles que não estão familiarizados com Haskell, Flapjax, http://www.flapjax-lang.org/ é uma implementação de programação reativa funcional sobre JavaScript.
fonte
As palavras-chave que você está procurando são "programação reativa funcional" (FRP).
Conal Elliott e alguns outros criaram um pouco da indústria caseira ao tentar encontrar a abstração certa para o FRP. Existem várias implementações de conceitos de FRP em Haskell.
Você pode considerar começar com o artigo "Programação reativa funcional por push-pull" mais recente da Conal , mas existem várias outras implementações (mais antigas), algumas delas vinculadas no site haskell.org . Conal tem um talento especial para cobrir todo o domínio, e seu artigo pode ser lido sem referência ao que veio antes.
Para ter uma idéia de como essa abordagem pode ser usada para o desenvolvimento da GUI, convém examinar o Fudgets , que, embora esteja ficando um pouco longo nos dias de hoje, sendo projetado em meados dos anos 90, apresenta uma abordagem sólida de FRP ao design da GUI.
fonte
O Windows Presentation Foundation é uma prova de que a abordagem funcional funciona muito bem para a programação da GUI. Possui muitos aspectos funcionais e o código WPF "bom" (pesquisa pelo padrão MVVM) enfatiza a abordagem funcional sobre o imperativo. Eu poderia bravamente afirmar que o WPF é o kit de ferramentas GUI funcional do mundo real mais bem-sucedido :-)
O WPF descreve a interface do usuário em XAML (embora você possa reescrevê-la para aparência funcional em C # ou F # também), portanto, para criar alguma interface de usuário, escreva:
Além disso, o WPF também permite descrever declarativamente animações e reações a eventos usando outro conjunto de tags declarativas (novamente, a mesma coisa pode ser escrita como código C # / F #):
Na verdade, acho que o WPF tem muitas coisas em comum com o FRP de Haskell (embora eu acredite que os designers do WPF não sabiam sobre o FRP e seja um pouco lamentável - o WPF às vezes se sente um pouco estranho e pouco claro se você estiver usando o recurso funcional. ponto de vista).
fonte
INotifyPropertyChanged
de todas as coisas), parece antitético ao FP para mim. Definitivamente, não sou especialista em FP, e talvez esteja focando muito no aspecto da imutabilidade em oposição ao aspecto declarativo, mas estou tendo problemas para ver como o padrão MVVM (como normalmente usado) é um exemplo de FP.INotifyPropertyChanged
é apenas uma função de atualização que você passa para onde quer que precise lidar com as atualizações da GUI - é uma correção de latência.Na verdade, eu diria que a programação funcional (F #) é uma ferramenta muito melhor para a programação da interface do usuário do que, por exemplo, o C #. Você só precisa pensar sobre o problema de maneira um pouco diferente.
Discuto esse tópico no meu livro de programação funcional no Capítulo 16, mas há um trecho gratuito disponível , que mostra (IMHO) o padrão mais interessante que você pode usar no F #. Digamos que você queira implementar o desenho de retângulos (o usuário aperta o botão, move o mouse e solta o botão). Em F #, você pode escrever algo como isto:
Essa é uma abordagem muito imperativa (no estilo F # pragmático usual), mas evita o uso de estado mutável para armazenar o estado atual do desenho e para armazenar a localização inicial. Pode ser ainda mais funcional: escrevi uma biblioteca que faz isso como parte da minha tese de mestrado, que deve estar disponível no meu blog nos próximos dias.
A Programação Reativa Funcional é uma abordagem mais funcional, mas acho um pouco mais difícil de usar, pois depende de recursos Haskell bastante avançados (como setas). No entanto, é muito elegante em um grande número de casos. Sua limitação é que você não pode codificar facilmente uma máquina de estado (que é um modelo mental útil para programas reativos). Isso é muito fácil usando a técnica F # acima.
fonte
IObservable
.Quer você esteja em uma linguagem funcional / OO híbrida como F # ou OCaml, ou em uma linguagem puramente funcional como Haskell, onde os efeitos colaterais são relegados à mônada de IO, geralmente ocorre uma tonelada do trabalho necessário para gerenciar uma GUI é muito mais um "efeito colateral" do que um algoritmo puramente funcional.
Dito isto, houve algumas pesquisas realmente sólidas sobre GUIs funcionais . Existem até alguns kits de ferramentas funcionais (principalmente), como Fudgets ou FranTk .
fonte
Você pode conferir a série de Don Syme no F #, onde a demo está criando um gui. o link a seguir é para a terceira parte da série (você pode vincular a partir daí para as outras duas partes).
Usar o F # para o desenvolvimento do WPF seria um paradigma da GUI muito interessante ...
http://channel9.msdn.com/shows/Going+Deep/C9-Lectures-Dr-Don-Syme-Introduction-to-F-3-of-3/
fonte
Uma das idéias de abertura da mente por trás da Programação Reativa Funcional é ter uma função de manipulação de eventos produzindo AMBOS a reação a eventos E a próxima função de manipulação de eventos. Assim, um sistema em evolução é representado como uma sequência de funções de manipulação de eventos.
Para mim, aprender Yampa tornou-se um ponto crucial para entender adequadamente essa coisa de produzir funções. Existem alguns papéis interessantes sobre o Yampa. Eu recomendo The Yampa Arcade:
http://www.cs.nott.ac.uk/~nhn/Talks/HW2003-YampaArcade.pdf (slides, PDF) http://www.cs.nott.ac.uk/~nhn/Publications/hw2003. pdf (artigo completo, PDF)
Existe uma página wiki no Yampa em Haskell.org
http://www.haskell.org/haskellwiki/Yampa
Página inicial original do Yampa:
http://www.haskell.org/yampa (infelizmente está quebrado no momento)
fonte
Desde que essa pergunta foi feita pela primeira vez, a programação reativa funcional tornou-se um pouco mais mainstream pela Elm.
Sugiro que verifique em http://elm-lang.org , que também possui alguns tutoriais interativos verdadeiramente excelentes sobre como criar uma GUI totalmente funcional no navegador.
Ele permite criar GUI totalmente funcionais, onde o código que você precisa fornecer consiste apenas em funções puras. Pessoalmente, achei muito mais fácil entrar do que as várias estruturas da GUI Haskell.
fonte
A palestra de Elliot sobre FRP pode ser encontrada aqui .
Além disso, não é realmente uma resposta, mas uma observação e alguns pensamentos : de alguma forma, o termo "GUI funcional" parece um pouco com um oxímoro (pureza e IO no mesmo termo).
Mas meu entendimento vago é que a programação funcional da GUI é sobre definir declarativamente uma função dependente do tempo que recebe a entrada do usuário (real) dependente do tempo e produz saída GUI dependente do tempo.
Em outras palavras, essa função é definida declarativamente como uma equação diferencial, em vez de um algoritmo usar imperativamente o estado mutável.
Assim, no FP convencional, utiliza-se funções independentes do tempo, enquanto no FRP, utiliza-se funções dependentes do tempo como blocos de construção para descrever um programa.
Vamos pensar em simular uma bola em uma mola com a qual o usuário possa interagir. A posição da bola é a saída gráfica (na tela), o usuário pressionando a bola pressiona a tecla (entrada).
A descrição deste programa de simulação em FRP (de acordo com o meu entendimento) é feita por uma única equação diferencial (declarativa): aceleração * massa = - extensão da mola * constante da mola + Força exercida pelo usuário.
Aqui está um vídeo no ELM que ilustra esse ponto de vista.
fonte
A partir de 2016, existem várias estruturas FRP relativamente maduras para Haskell, como Sodium e Reflex (mas também Netwire).
O livro Manning sobre Programação Reativa Funcional mostra a versão Java do sódio, para exemplos de trabalho, e ilustra como uma base de código da FRP GUI se comporta e escala em comparação com abordagens imperativas e baseadas em atores.
Há também um artigo recente sobre FRP Arrowized e a perspectiva de incorporar efeitos colaterais, IO e mutações em um ambiente de FRP puro e cumpridor da lei: http://haskell.cs.yale.edu/wp-content/uploads/2015/10/ dwc-yale-formatted-dissertation.pdf .
Também digno de nota é que as estruturas JavaScript como ReactJS e Angular e muitas outras já estão ou estão adotando uma abordagem FRP ou funcional para obter componentes de GUI escaláveis e composíveis.
fonte
Linguagens de marcação como o XUL permitem criar uma GUI de maneira declarativa.
fonte
Para resolver isso, postei algumas idéias minhas usando F #,
http://fadsworld.wordpress.com/2011/04/13/f-in-the-enterprise-i/ http://fadsworld.wordpress.com/2011/04/17/fin-the-enterprise-ii- 2 /
Também estou planejando fazer um tutorial em vídeo para concluir a série e mostrar como o F # pode contribuir na programação de UX.
Eu só estou falando no contexto de F # aqui.
-Fahad
fonte
Todas essas outras respostas são criadas com base na programação funcional, mas tomam muitas de suas próprias decisões de design. Uma biblioteca que é construída basicamente inteiramente a partir de funções e tipos de dados abstratos simples é
gloss
. Aqui está o tipo para suaplay
função da fonteComo você pode ver, ele funciona inteiramente fornecendo funções puras com tipos abstratos simples, com os quais outras bibliotecas o ajudam.
fonte
A inovação mais aparente observada por pessoas novas em Haskell é que existe uma separação entre o mundo impuro que se preocupa em se comunicar com o mundo exterior e o mundo puro da computação e algoritmos. Uma pergunta freqüente para iniciantes é "Como posso me livrar
IO
, ou seja, converterIO a
ema
?" O caminho para isso é usar mônadas (ou outras abstrações) para escrever código que execute efeitos de IO e encadeamentos. Esse código reúne dados do mundo exterior, cria um modelo, faz algumas computações, possivelmente empregando código puro, e gera o resultado.No que diz respeito ao modelo acima, não vejo nada de errado em manipular GUIs na
IO
mônada. O maior problema que surge desse estilo é que os módulos não são mais compostáveis, ou seja, perco a maior parte do meu conhecimento sobre a ordem de execução global das instruções no meu programa. Para recuperá-lo, tenho de aplicar um raciocínio semelhante ao do código da GUI concorrente e imperativo. Enquanto isso, para um código não-GUI impuro, a ordem de execução é óbvia por causa da definiçãoIO
do>==
operador da mônada (pelo menos enquanto houver apenas um encadeamento). Para código puro, isso não importa, exceto em casos extremos para aumentar o desempenho ou evitar avaliações resultantes⊥
.A maior diferença filosófica entre console e E / S gráfica é que os programas que implementam o primeiro são geralmente escritos em estilo síncrono. Isso é possível porque existe (deixando de lado os sinais e outros descritores de arquivos abertos) apenas uma fonte de eventos: o fluxo de bytes normalmente chamado
stdin
. As GUIs são inerentemente assíncronas e precisam reagir a eventos do teclado e cliques do mouse.Uma filosofia popular de executar IO assíncrona de uma maneira funcional é chamada de Programação Reativa Funcional (FRP). Recentemente, houve muita tração em linguagens impuras e não funcionais, graças a bibliotecas como o ReactiveX e estruturas como o Elm. Em poucas palavras, é como visualizar elementos da GUI e outras coisas (como arquivos, relógios, alarmes, teclado, mouse) como fontes de eventos, chamadas "observáveis", que emitem fluxos de eventos. Estes eventos são combinados usando operadores conhecidos, como
map
,foldl
,zip
,filter
,concat
,join
, etc., para produzir novos fluxos. Isso é útil porque o próprio estado do programa pode ser visto comoscanl . map reactToEvents $ zipN <eventStreams>
do programa, ondeN
é igual ao número de observáveis já considerados pelo programa.Trabalhar com observáveis de FRP torna possível recuperar a composição porque os eventos em um fluxo são ordenados a tempo. O motivo é que a abstração do fluxo de eventos torna possível visualizar todos os observáveis como caixas pretas. Por fim, a combinação de fluxos de eventos usando operadores devolve algumas ordens locais na execução. Isso me obriga a ser muito mais honesto em relação aos invariantes em que meu programa realmente se baseia, semelhante à maneira como todas as funções no Haskell precisam ser referencialmente transparentes: se eu quiser extrair dados de outra parte do meu programa, preciso ser explícito. O anúncio declara um tipo apropriado para minhas funções. (A mônada de IO, sendo uma linguagem específica de domínio para escrever código impuro, evita isso efetivamente)
fonte
A programação funcional pode ter mudado desde quando eu estava na universidade, mas pelo que me lembro, o ponto principal de um sistema de programação funcional era impedir o programador de criar qualquer "efeito colateral". No entanto, os usuários compram software devido aos efeitos colaterais criados, por exemplo, atualizando uma interface do usuário.
fonte