2015-01-20 3 views
0

객체 지향 언어에서 공통적 인 추상 팩토리 디자인 패턴을 함수 언어로 구현하는 방법을 궁금합니다. 특히 하스켈 구현에 관심이 있습니다.하스켈의 추상 팩터 리

그것은 컴파일러처럼 보이는
Could not deduce (p ~ FirstProduct) 
from the context (Product p) 
    bound by the type signature for 
      createProduct :: Product p => FirstFactory -> p 
    at test.hs:14:3-15 
    ‘p’ is a rigid type variable bound by 
     the type signature for 
     createProduct :: Product p => FirstFactory -> p 
     at test.hs:14:3 
Relevant bindings include 
    createProduct :: FirstFactory -> p (bound at test.hs:14:3) 
In the expression: FirstProduct 
In an equation for ‘createProduct’: createProduct _ = FirstProduct 

이 만족되지 않습니다 :

class Product p where 
    toString :: p -> String 

class Factory f where 
    createProduct :: Product p => f -> p 

data FirstProduct = FirstProduct 
data FirstFactory = FirstFactory 

instance Product FirstProduct where 
    toString _ = "first product" 

instance Factory FirstFactory where 
    createProduct _ = FirstProduct 

이 코드를 컴파일, 다음과 같은 오류 대신 반환됩니다

나는 형 클래스를 사용하여 패턴을 구현하기 위해 노력 구현은 createProduct이며 특히 반환 값이 있습니다. 나는 Product 타입 클래스의 어떤 인스턴스를 반환하는 것이 트릭을 할 수는 있지만 분명히하지는 않습니다.

Abstract Factory와 비슷한 것이 Haskell에서 구현 될 수 있는지 또는 내 접근 방식이 완전히 잘못되었는지 알고 싶습니다. 비슷한 결과를 얻기 위해 사용할 수있는 다른 "패턴"이 있습니까?

편집

는 제안과 leftaroundabout의 설명에 따르면, I 형 클래스를 오용하지 않고 내 요구를 충족 다른 솔루션을 함께했다. 해결책은 아마도 개선 될 수 있었지만, 지금이 순간이 내가 얻을 수 있었던 최선의 것입니다.

data FirstProduct = FirstProduct 

firstSystem :: ProductSystem FirstProduct 
firstSystem = ProductSystem create toString 
    where 
    create = FirstProduct 
    toString p = "first" 

data SecondProduct = SecondProduct 

secondSystem :: ProductSystem SecondProduct 
secondSystem = ProductSystem create toString 
    where 
    create = SecondProduct 
    toString p = "second" 

다른 곳에서 그들의 구체적인 요구에 ProductSystem의 "구현"을 제공 할 수있는 라이브러리의

data ProductSystem p = ProductSystem {create :: p, toString :: p -> String } 

productUser :: ProductSystem p -> String 
productUser system = toString system $ create system 

일부 사용자 :

라이브러리는 다음과 같은 일을 정의해야합니다 두 부분은 원하는 동작을 실행하기 위해 통합 될 수 있습니다.

productUser firstSystem 
productUser secondSystem 
+11

추상적 인 팩토리 패턴은 언어의 무능함에 대해 다소 어리석게 복잡한 방식으로 작동하므로 ** 함수 **를 정의하면됩니다. 왜 하스켈에서 그걸 필요로 하죠? - 더 객관적인 발언 : 하스켈 타입 클래스는 OO 언어의 클래스 인 것의 좋은 드롭 인 것은 아닙니다. Haskell에서 Abstract Factory와 같은 모델을 만들고 싶다면 "클래스"에 대해 '데이터'를 사용하는 것이 좋습니다. – leftaroundabout

+1

'createProduct'의 타입은 구현이'FirstProduct'의 인스턴스만을 리턴 할 수있는 반면'Product'의 인스턴스를 생성 할 수 있음을 나타냅니다. – Lee

+1

Haskell에서 OO를 수행하는 방법에 대한 자세한 정보는 https://www.haskell.org/haskellwiki/OOP_vs_type_classes, http://stackoverflow.com/questions/20184286/object-oriented-programming-in- haskell/20188103 및 https://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/. – leftaroundabout

답변

5

이미 말했듯이 전체적인 아이디어는 쓸모 없습니다. 하스켈에 추상 공장이 필요하지 않습니다. 하지만 그건 그렇고, 여기 당신의 특별한 시도가 컴파일되지 않는 이유가 있습니다.


서명

createProduct :: Product p => f -> p 

은 분명히 생각하지 의미 : 자바,이 생각하는 요구하지 않는, 내가 Product의 서브 클래스의 어떤 객체를 생성 할 것 "말할 것입니다. " 하스켈에서 서브 클래스가 이 아닌 –은 서브 타입입니다! – 이것은 "에 대해 Product (특정!) 인스턴스에 대해 요청합니다. 구체적인 유형의 개체를 알려 드리겠습니다." 가능하지 않습니다. FirstFactorySecondProduct을 제공 할 수 없습니다.

당신이 말하고자하는 것을 표현하려면 "모든 하위 클래스"를 포함하는 명시 적 래퍼가 필요합니다.우리는이 존재, 그것은 이렇게 쓰여 있다고 호출이와

{-# LANGUAGE GADTs  #-} 

data AnyProduct where 
    AnyProduct :: Product p => p -> AnyProduct 

, 당신은 어떤 yourProduct :: AnyProduct를 들어

class Factory f where 
    createProduct :: f -> AnyProduct 

을 작성할 수 있습니다, 당신은이 방법의 "toString 메소드를 호출"할 수 있습니다

 ... 
     productString = case yourProduct of 
         AnyProduct p -> toString p 
     ... 

하지만 실제로는 이므로 할 수 있습니다. AnyProduct 값 (예 : OO 언어에서와 같이 알 수없는 하위 클래스의 필드/메소드에 액세스 할 수 없음)을 사용하면 전체 AnyProduct 유형은 실제로 String과 완전히 같습니다. 그리고 동일한 논증에 의해, AnyFactory은 다시 그와 동등합니다. 그러니까 기본적으로, 당신이 게시 된 전체 코드가

Existentials 매우 generally frowned upon입니다 ...

type Product = String 

동일합니다, 당신은 단지 OO 언어 서브 클래스와 함께 할 이유만으로하지 아무것도, 특별한 경우를 사용해야합니다 .

+0

이것은 흥미로운 것으로 보이지만, 앞서 언급 한 것처럼 내 문제는 훨씬 간단한 구조로 해결 될 수 있습니다. 나는 나의 마음에 온 다른 해결책을 추가하기 위해 나의 질문을 편집했다. 어쨌든, 오늘 나는 확실히 뭔가를 배웠다! – frm

관련 문제