인터페이스의 기능적 프로그래밍 대안은 무엇입니까?


15

"기능적"스타일로 프로그래밍하려면 인터페이스를 무엇으로 바꾸어야합니까?

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) 기능이 서로 관련이 있는지 확인하십시오.


당신은하지 않을 것입니다. 데이터 유형 에 대한 인터페이스 는 완벽합니다 (불변의 객체를 선호하지만).
Telastyn

1
SICP의 2 장은 이것에 관한 것입니다.
user16764

7
질문을 다시 읽은 후에는 어떤 특정 기능을 수행하려고하는지 궁금합니다. 당신이 요구하는 것처럼 보이지 않는 기능적 스타일의 인스턴스에 대해 oo 스타일의 부작용 프로그램을 수행하는 방법입니다.
Jimmy Hoffa

대답은 언어에 따라 다릅니다. Clojure에서는 clojure.org/protocols 를 사용할 수 있습니다 . 여기서 소프트 영역은 함수가 작동해야하는 매개 변수 유형입니다. 즉 객체입니다.
Job

1
간단하게 만드십시오 : 메소드 포인터를 포함하는 구조체와 객체 인스턴스에서 초기화하는 함수. 왜 하스켈인가? ;)
mlvljr

답변:


6

함수형 프로그래밍을 명령형 프로그래밍보다 얇은 비니어로 취급하지 마십시오. 구문상의 차이 이상의 것이 있습니다.

이 경우 GetID객체의 고유성을 의미 하는 방법이 있습니다. 기능적 프로그램 작성에 대한 좋은 접근 방식은 아닙니다. 아마도 당신이 해결하려는 문제를 우리에게 말해 줄 수 있고 우리는 당신에게 더 의미있는 조언을 줄 수 있습니다.


3
"당신은 러시아어로 생각 해야합니다 ."
Ðаn

그럴 수 있지; 내 진짜 문제는 특별히 흥미롭지 않습니다. 나는 C # ( github.com/JDanielSmith/Projects/tree/master/PictureOfTheDay 에서 실제로 코드를보고 싶다면)에서 잘 작동하지만 더 기능적인 스타일로하는 것이 재미있을 것입니다. 여전히 C #을 사용하고 있습니다.
Ðаn

1
Ðаn @이 정말인가 파이어 폭스 (필름) 따옴표 (즉 때문에 굉장 이있는 경우)? 아니면 다른 곳에서 사용됩니까?
icc97

2
필자가 동의 한 것처럼 그것은 명령형에서 기능적 프로그래밍으로의 완전한 패러다임 전환이지만, 명령 식으로 작성된 몇 줄의 코드 줄이 더 많습니다. 따라서 거대한 시스템을 위해 작성된 더 많은 코너 사례가 명령형 프로그래밍에서 발견되었습니다. 명령형 프로그래밍에는 많은 모범 사례가 있으며 이러한 기술을 번역 할 수 있는지 또는 FP에서 문제가 아닌지를 아는 것은 가치있는 질문입니다. FP에서 끔찍한 코드를 작성하는 것이 가능하므로 이러한 종류의 질문은 FP의 좋은 부분도 강조해야합니다.
icc97

11

Haskell과 그 파생물에는 인터페이스와 유사한 유형 클래스가 있습니다. 캡슐화 방법에 대해 묻는 것처럼 들리지만 유형 시스템에 관한 질문입니다. hindley Milner 유형 시스템은 기능적 언어에서 일반적이며 언어마다 다양한 방식으로이를 수행하는 데이터 유형이 있습니다.


5
타입 클래스의 경우 +1-Haskell 타입 클래스와 자바 인터페이스의 주요 차이점은 타입 클래스가 둘 다 개별적으로 선언 된 타입과 연관되어 있다는 것 입니다. 기존 "인터페이스"를 사용하여 새 유형에 액세스하는 것만 큼 쉽게 새 "인터페이스"를 통해 이전 유형을 사용할 수 있습니다. 데이터 숨기기의 경우 모듈에서 유형의 구현을 숨 깁니다. 에펠 탑의 Bertrand Meyer에 따르면 OOP 클래스 일종의 모듈입니다.
Steve314

5

함수가 여러 입력을 처리 할 수있는 몇 가지 방법이 있습니다.

첫째로 가장 흔한 것은 파라 메트릭 다형성입니다.

이것은 함수가 임의의 타입에 작용하게합니다 :

--Haskell Example
id :: a -> a --Here 'a' is just some arbitrary type
id myRandomThing = myRandomThing

head :: [a] -> a
head (listItem:list) = listItem

어느 것이 좋지만 OO 인터페이스에있는 동적 디스패치를 ​​제공하지는 않습니다. 이 Haskell에는 typeclass가 있고 Scala에는 암시 적 등이 있습니다.

class Addable a where
   (<+>) :: a -> a -> a
instance Addable Int where
   a <+> b = a + b
instance Addable [a] where
   a <+> b = a ++ b

--Now we can get that do something similar to OO (kinda...)
addStuff :: (Addable a) => [a] -> a
-- Notice how we limit 'a' here to be something Addable
addStuff (x:[]) = x
addStuff (x:xs) = x <+> addStuff xs
-- In better Haskell form
addStuff' = foldl1 <+>

이 두 메커니즘 사이에서, 당신은 당신의 타입에 대한 모든 종류의 복잡하고 흥미로운 행동을 표현할 수 있습니다.


1
답변의 언어가 질문의 언어와 일치하지 않을 때 sintax 강조 힌트를 추가 할 수 있습니다 . 예를 들어 제안 된 편집을 참조하십시오.
hugomg

1

기본 규칙은 FP 프로그래밍 기능에서 객체가 OO 프로그래밍에서 수행하는 것과 동일한 작업을 수행한다는 것입니다. 당신은 그들의 메소드를 호출 할 수 있고 (어쨌든 "call"메소드) 캡슐화 된 내부 규칙에 따라 응답합니다. 특히, 모든 적절한 FP 언어를 사용하면 함수에 클로저 / 어휘 범위를 지정하여 "인스턴스 변수"를 사용할 수 있습니다.

var make_OO_style_counter = function(){
   return {
      counter: 0
      increment: function(){
          this.counter += 1
          return this.counter;
      }
   }
};

var make_FP_style_counter = function(){
    var counter = 0;
    return fucntion(){
        counter += 1
        return counter;
    }
};

다음 질문은 인터페이스가 무엇을 의미합니까? 하나의 접근 방식은 공칭 인터페이스를 사용하는 것입니다 (공통 인터페이스에 따르면 인터페이스에 적합 함).이 방법은 일반적으로 사용하는 언어에 따라 달라 지므로 후자를 위해 남겨 두십시오. 인터페이스를 정의하는 다른 방법은 구조적 방법으로, 어떤 매개 변수가 수신하고 반환하는지 확인합니다. 이것은 동적 오리 형식 언어에서 볼 수있는 일종의 인터페이스이며 모든 FP와 매우 잘 맞습니다. 인터페이스는 입력 매개 변수의 유형과 함수에 반환되는 유형입니다. 인터페이스에 맞는 올바른 유형!

따라서 인터페이스와 일치하는 객체를 나타내는 가장 간단한 방법은 단순히 기능 그룹을 갖는 것입니다. 일반적으로 함수를 일종의 레코드로 포장하여 함수를 별도로 전달하는 추악함을 극복합니다.

var my_blarfable = {
 get_name: function(){ ... },
 set_name: function(){ ... },
 get_id:   function(){ ... }
}

do_something(my_blarfable)

노출 된 기능이나 기능 레코드를 사용하면 많은 상용구없이 "무 지방"방식으로 대부분의 일반적인 문제를 해결할 수 있습니다. 그보다 더 고급 기능이 필요한 경우 언어에 따라 추가 기능이 제공되기도합니다. 언급 된 사람들의 한 예는 Haskell 유형 클래스입니다. 유형 클래스는 본질적으로 유형을 해당 함수 레코드 중 하나와 연관 시키며 사전을 암시하여 적절하게 자동으로 내부 함수에 전달하도록 항목을 작성할 수있게합니다.

-- Explicit dictionary version
-- no setters because haskell doesn't like mutable state.
data BlargDict = BlargDict {
    blarg_name :: String,
    blarg_id   :: Integer
}

do_something :: BlargDict -> IO()
do_something blarg_dict = do
   print (blarg_name blarg_dict)
   print (blarg_id   blarg_dict)

-- Typeclass version   
class Blargable a where
   blag_name :: a -> String
   blag_id   :: a -> String

do_something :: Blargable a => a -> IO
do_something blarg = do
   print (blarg_name blarg)
   print (blarg_id   blarg)

그러나 유형 클래스에 대해 유의해야 할 중요한 점은 사전이 사전과 OO 버전에서 발생하는 것과 같은 값이 아니라 유형과 연관되어 있다는 것입니다. 이는 타입 시스템이 "타입"을 혼합 할 수 없음을 의미합니다 [1]. "blargables"목록이나 blargables로 가져 오는 이진 함수를 원한다면 typeclasses는 모든 것을 같은 유형으로 제한하지만 사전 접근 방식은 다른 출처의 blargable을 가질 수 있습니다 (어떤 버전이 더 나은지 당신이 무엇인지에 달려 있습니다) 하기)

[1] "기존 유형"을 수행하는 고급 방법이 있지만 일반적으로 문제가되지 않습니다.


0

언어마다 다를 것이라고 생각합니다. 나는 lispy 배경에서 왔습니다. 대부분의 경우 상태와의 인터페이스는 기능 모델을 어느 정도 손상시킵니다. 예를 들어 CLOS는 LISP의 기능이 떨어지고 명령형 언어에 더 가깝습니다. 일반적으로 고급 기능과 결합 된 필수 기능 매개 변수는 아마도 원하는 것입니다.

;; returns a function of the type #'(lambda (x y z &optional a b c)

(defun get-higher-level-method-impl (some-type-of-qualifier) 
    (cond ((eq 'foo) #'the-foo-version)
          ((eq 'bar) #'the-bar-version)))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.