Если я хочу программировать в «функциональном» стиле, чем бы заменить интерфейс?
interface IFace
{
string Name { get; set; }
int Id { get; }
}
class Foo : IFace { ... }
Может быть Tuple<>
?
Tuple<Func<string> /*get_Name*/, Action<String> /*set_Name*/, Func<int> /*get_Id*/> Foo;
Единственная причина, по которой я в первую очередь использую интерфейс, заключается в том, что я всегда хочу, чтобы были доступны определенные свойства / методы.
Редактировать: более подробно о том, что я думаю / пытаюсь.
Скажем, у меня есть метод, который принимает три функции:
static class Blarf
{
public static void DoSomething(Func<string> getName, Action<string> setName, Func<int> getId);
}
С экземпляром Bar
я могу использовать этот метод:
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);
Но это немного болезненно, поскольку я должен упомянуть bar
три раза за один звонок. Кроме того, я не собираюсь предоставлять вызывающим функциям функции из разных экземпляров.
Blarf.DoSomething(bar1.GetName, bar2.SetName, bar3.GetId); // NO!
В C # это interface
один из способов справиться с этим; но это кажется очень объектно-ориентированным подходом. Мне интересно, есть ли более функциональное решение: 1) передать группу функций вместе, и 2) убедиться, что функции должным образом связаны друг с другом.
Ответы:
Не относитесь к функциональному программированию как к тонкой оболочке императивного программирования; есть гораздо больше, чем просто синтаксическая разница.
В этом случае у вас есть
GetID
метод, который подразумевает уникальность объектов. Это не очень хороший подход к написанию функциональных программ. Возможно, вы могли бы рассказать нам о проблеме, которую пытаетесь решить, и мы могли бы дать вам более полезный совет.источник
Haskell и его производные имеют классы типов, похожие на интерфейсы. Хотя, похоже, вы спрашиваете о том, как сделать инкапсуляцию, а это вопрос о системах типов. Система типов Хиндли Милнера широко распространена в функциональных языках и имеет типы данных, которые делают это для вас по-разному в разных языках.
источник
Есть несколько способов разрешить функции работать с несколькими входами.
Первый и самый распространенный: параметрический полиморфизм.
Это позволяет функции действовать на произвольные типы:
Это хорошо, но не дает вам динамического распределения, которое есть у интерфейсов OO. Для этого у Haskell есть классы типов, у Scala есть имплициты и т. Д.
Между этими двумя механизмами вы можете выражать всевозможные сложные и интересные поведения на ваших типах.
источник
Основное правило заключается в том, что в программировании на FP функции выполняются так же, как объекты в OO-программировании. Вы можете вызывать их методы (ну, в любом случае, метод "call"), и они отвечают согласно некоторым инкапсулированным внутренним правилам. В частности, каждый приличный язык FP позволяет вам иметь «переменные экземпляра» в вашей функции с замыканиями / лексическими ограничениями.
Теперь следующий вопрос: что вы подразумеваете под интерфейсом? Один из подходов заключается в использовании номинальных интерфейсов (он соответствует интерфейсу, если он говорит, что это так) - обычно он во многом зависит от того, какой язык вы используете, поэтому оставим его для последнего. Другим способом определения интерфейса является структурный способ, позволяющий увидеть, какие параметры получать и возвращать. Это тот интерфейс, который вы обычно видите в динамических языках типа утка, и он очень хорошо подходит для всех FP: интерфейс - это просто типы входных параметров для наших функций и типы, которые они возвращают, поэтому все функции, соответствующие правильные типы соответствуют интерфейсу!
Следовательно, наиболее простой способ представления объекта, соответствующего интерфейсу, состоит в том, чтобы просто иметь группу функций. Обычно вы обходите безобразие передачи функций по отдельности, упаковывая их в какую-то запись:
Использование обнаженных функций или записей функций будет иметь большое значение для решения большинства ваших общих проблем «без жира» без тонны образцов. Если вам нужно что-то более продвинутое, иногда языки предоставляют вам дополнительные возможности. Один пример, который упоминали люди, это классы типа Haskell. Классы типов по существу связывают тип с одной из этих записей функций и позволяют вам писать вещи, чтобы словари были неявными и автоматически передавались внутренним функциям по мере необходимости.
Однако следует отметить одну важную вещь, касающуюся классов типов: словари связаны с типами, а не со значениями (например, что происходит в словаре и версиях ОО). Это означает, что система типов не позволяет смешивать «типы» [1]. Если вы хотите получить список "blargables" или двоичную функцию, заменяющую blargables, то классы типов будут ограничивать все одним и тем же типом, в то время как подход с использованием словаря позволит вам иметь blargables различного происхождения (какая версия лучше зависит от того, кто вы есть) делать)
[1] Существуют продвинутые способы создания «экзистенциальных типов», но, как правило, это не стоит проблем.
источник
Я думаю, что это будет зависеть от языка. Я родом из липы. Во многих случаях интерфейсы с состоянием до некоторой степени нарушают функциональную модель. Так, например, в CLOS LISP менее функциональный и ближе к императивному языку. Как правило, требуемые параметры функции в сочетании с методами более высокого уровня - это, вероятно, то, что вы ищете.
источник