인스턴스가 재귀 데이터 유형 인 유형 클래스에 대해 패턴 일치를 패턴 화하는 방법은 무엇입니까?

스벤 윌리엄슨

이 질문은 typeclass 값에 대한 패턴 일치 방법 에 대한 후속 조치입니다 . .

저는 1 차 논리로 애완 동물 프로젝트를 시작하고 있으며이를 위해 Haskell을 사용하기로 결정했습니다. 내 첫 번째 장애물은 '1 차 논리 공식'을 정의하는 것이므로 데이터 유형은 다음과 같습니다.

data Formula v  = Belong v v                      -- x in y
                | Bot                             -- False
                | Imply (Formula v) (Formula v)   -- p -> q
                | Forall v (Formula v)            -- forall x, p

그러나 구현 세부 사항을 기반으로 코드를 작성하는 것을 꺼리고 마음이 바뀌거나 대체 구현으로 기능을 재사용하려는 경우 유형 클래스를 사용하여 세부 정보를 추상화하고 싶습니다.

class FirstOrder m where
  belong    :: v -> v -> m v
  bot       :: m v
  imply     :: m v -> m v -> m v
  forall    :: v -> m v -> m v
  asFormula :: m v -> Formula v

(위 링크에서 제안한 asFormula대로)을 ViewPatterns( 를) 사용하기 위해 마지막 함수 추가 하여이 유형 클래스의 값에 대한 패턴 일치를 수행 할 수 있습니다.

이제 간단한 함수를 정의하고 싶다고 가정합니다.

subst :: (FirstOrder m) => (v -> w) -> m v -> m w

소정의 맵핑에 따라 식의 변수되는 대체품 f::v -> w(Feel로 좋아 fmap) 화학식 그래서 belong x y에 매핑 belong (f x) (f y)등을 사용하여 다음 ViewPatterns:

subst f (asFormula -> Belong x y) = belong (f x) (f y)

여태까지는 그런대로 잘됐다...

그러나 쓰려고 할 때 subst f p->q = (subst f p) -> (subst f q):

subst f (asFormula -> Imply p q)  = imply (subst f p) (subst f q)

패턴 매칭 바인딩 : 나는 그것을 생각 오는 유형의 오류가 완벽한 의미가 얻을 수 pq유형의 요소에 Formula v원하는 형식에 반대 m v.

이제 문제를 볼 수 fromFormula있으며 유형 클래스에 함수를 추가 하여 유형으로 다시 변환 하여 문제를 해결하는 방법을 생각할 수도 m v있지만 성능 관점에서 보면 이것이 미쳤다고 asFormula생각합니다. ), 코드를 일반화하기 위해 지불해야하는 엄청난 대가입니다.

그래서 지금은 자유 대수 (재귀 적 데이터 유형)에 대한 구조적 재귀에 의해 간단한 함수를 정의하려고하지만, 구현 세부 사항을 추상화하고 (데이터 유형이 아닌 유형 클래스에서 코드를 작성하려는) 욕구는 불가능한 입장 인 것 같습니다.

탈출구가 있습니까, 아니면 추상화를 잊고 재귀 데이터 유형으로 작업해야합니까?

이것은 과도한 일반화로 보이지만 어쨌든 무시합시다.

명시적인 F- (공-) 대수와 고정 소수점으로 해결할 수 있습니다.

data FormulaF v k
   = Belong v v                      -- x in y
   | Bot                             -- False
   | Imply (k v) (k v)               -- p -> q
   | Forall v (k v)                  -- forall x, p

newtype Formula v = Formula (FormulaF v Formula)      
   -- fixed point. You might not need it, but it's nice to have.
   -- 

그런 다음 할 수 있습니다.

class FirstOrder m where
  belong    :: v -> v -> m v
  bot       :: m v
  imply     :: m v -> m v -> m v
  forall    :: v -> m v -> m v
  asFormula :: m v -> FormulaF v m

subst :: (FirstOrder m) => (v -> w) -> m v -> m w
subst f (asFormula -> Belong x y) = belong (f x) (f y)
subst f (asFormula -> Imply p q)  = imply (subst f p) (subst f q)

asFormula전체 m v를 재귀 적으로 전체 수식으로 변환하지 않기 때문에 이제 작동해야 하지만 FormulaF v m표면적으로는 수식 (예 : 패턴과 일치하는 첫 번째 생성자)처럼 보이는 a로 변환 Imply되지만 내부 깊이는 여전히 m v.

이 지나치게 일반적인 접근 방식을 정말로 추구하고 싶다면 recursion-schemes, F- 대수와 F-coalgebras, 그리고 관련된 cata- / ana- / hylo- / para- / 어떤 형태를보아야 할 것입니다.

마지막으로 FP에서 OOP 디자인 패턴을 적용하지 않는 것이 좋습니다. 때때로 당신은 그런 식으로 무언가를 구둣 주를 할 수 있지만 그것은 종종 일관적일 수 있습니다. 예를 들어, Haskell에서 우리는 OOP 인터페이스에서 고정 된 양의 메서드를 가지고있는 것처럼 (그러나 개방 된 서브 클래스 집합) 고정 된 양의 생성자를 갖는 타입 (그러나 그것들에서 작동하는 개방형 함수 세트)에 꽤 익숙합니다. . 일반화를 시도 할 수 있지만 복잡하고 필요할 때만 수행해야합니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

Related 관련 기사

뜨겁다태그

보관