Se eu quiser programar em um estilo "funcional", com o que eu substituiria uma interface?
interface IFace
{
string Name { get; set; }
int Id { get; }
}
class Foo : IFace { ... }
Talvez um Tuple<>
?
Tuple<Func<string> /*get_Name*/, Action<String> /*set_Name*/, Func<int> /*get_Id*/> Foo;
A única razão pela qual estou usando uma interface em primeiro lugar é porque eu quero sempre certas propriedades / métodos disponíveis.
Edit: Mais alguns detalhes sobre o que estou pensando / tentando.
Digamos, eu tenho um método que leva três funções:
static class Blarf
{
public static void DoSomething(Func<string> getName, Action<string> setName, Func<int> getId);
}
Com uma instância de Bar
eu posso usar este método:
class Bar
{
public string GetName();
public void SetName(string value);
public int GetId();
}
...
var bar = new Bar();
Blarf.DoSomething(bar.GetName, bar.SetName, bar.GetId);
Mas isso é um pouco doloroso, como devo mencionar bar
três vezes em uma única ligação. Além disso, não pretendo que os chamadores forneçam funções de diferentes instâncias
Blarf.DoSomething(bar1.GetName, bar2.SetName, bar3.GetId); // NO!
Em C #, uma interface
é uma maneira de lidar com isso; mas isso parece ser uma abordagem muito orientada a objetos. Gostaria de saber se há uma solução mais funcional: 1) passar o grupo de funções juntos e 2) garantir que as funções estejam relacionadas corretamente.
Respostas:
Não trate a programação funcional como uma camada fina sobre a programação imperativa; há muito mais do que apenas uma diferença sintática.
Nesse caso, você tem um
GetID
método, o que implica exclusividade de objetos. Essa não é uma boa abordagem para escrever programas funcionais. Talvez você possa nos dizer o problema que está tentando resolver e poderíamos dar conselhos mais significativos.fonte
Haskell e seus derivados têm classes de tipos semelhantes às interfaces. Embora pareça que você está perguntando sobre como fazer o encapsulamento, que é uma pergunta sobre sistemas de tipos. O sistema do tipo Milley hindley é comum em idiomas funcionais e possui tipos de dados que fazem isso para você de maneira variável entre idiomas.
fonte
Existem algumas maneiras de permitir que uma função lide com várias entradas.
Primeiro e mais comum: Polimorfismo Paramétrico.
Isso permite que uma função atue em tipos arbitrários:
O que é legal, mas não fornece o envio dinâmico que as interfaces OO têm. Para este Haskell tem classes tipográficas, Scala tem implícitos, etc.
Entre esses dois mecanismos, você pode expressar todo tipo de comportamento complexo e interessante em seus tipos.
fonte
A regra básica é que, nas funções de programação FP, o mesmo trabalho que os objetos na programação OO. Você pode chamar os métodos deles (bem, o método "call" de qualquer maneira) e eles respondem de acordo com algumas regras internas encapsuladas. Em particular, cada linguagem FP decente permite que você tenha "variáveis de instância" em sua função com fechamentos / escopo lexical.
Agora, a próxima pergunta é o que você quer dizer com interface? Uma abordagem é usar interfaces nominais (em conformidade com a interface, se for o caso) - essa geralmente depende muito de qual idioma você está usando, então deixe para a última. A outra maneira de definir uma interface é a maneira estrutural, vendo quais parâmetros a coisa recebe e retorna. Esse é o tipo de interface que você costuma ver em linguagens dinâmicas e tipadas por patos e se encaixa muito bem com todo o FP: uma interface é apenas o tipo de parâmetro de entrada para nossas funções e o tipo que eles retornam. Todas as funções correspondem ao tipos corretos se encaixam na interface!
Portanto, a maneira mais direta de representar um objeto que corresponde a uma interface é simplesmente ter um grupo de funções. Você costuma contornar a feia de passar as funções separadamente, embalando-as em algum tipo de registro:
O uso de funções simples ou registros de funções ajudará bastante a solucionar a maioria dos problemas comuns de maneira "livre de gordura", sem toneladas de clichê. Se você precisar de algo mais avançado que isso, às vezes os idiomas oferecem recursos extras. Um exemplo mencionado pelas pessoas são as classes do tipo Haskell. As classes de tipo essencialmente associam um tipo a um desses registros de funções e permitem escrever coisas para que os dicionários sejam implícitos e passados automaticamente para as funções internas, conforme apropriado.
Uma coisa importante a ser observada sobre as classes de tipo, porém, é que os dicionários estão associados aos tipos, e não aos valores (como o que acontece no dicionário e nas versões OO). Isso significa que o sistema de tipos não permite misturar "tipos" [1]. Se você deseja uma lista de "blargables" ou uma função binária que leve a blargables, as classes de tipo restringirão tudo para ser do mesmo tipo, enquanto a abordagem do dicionário permitirá que você tenha blargables de diferentes origens (qual versão é melhor depende muito do que você é fazendo)
[1] Existem maneiras avançadas de fazer "tipos existenciais", mas geralmente não vale a pena.
fonte
Eu acho que vai ser um idioma específico. Eu venho de um fundo lispy. Em muitos casos, as interfaces com o estado quebram o modelo funcional em um grau. Portanto, o CLOS, por exemplo, é onde o LISP é menos funcional e mais próximo de uma linguagem imperativa. Geralmente, os parâmetros de função necessários combinados com métodos de nível superior provavelmente são o que você está procurando.
fonte