완전히 종속적 인 연결 만들기


10

연결에 대한 좋은 사실은 방정식에서 두 가지 변수를 아는 경우입니다.

a ++ b = c

그런 다음 세 번째를 알고 있습니다.

나는 기능적으로 의존성을 사용하기 위해이 아이디어를 내 자신의 concat에서 포착하고 싶습니다.

{-# Language DataKinds, GADTs, FlexibleContexts, FlexibleInstances, FunctionalDependencies, KindSignatures, PolyKinds, TypeOperators, UndecidableInstances #-}
import Data.Kind (Type)

class Concatable
   (m  :: k -> Type)
   (as :: k)
   (bs :: k)
   (cs :: k)
   | as bs -> cs
   , as cs -> bs
   , bs cs -> as
   where
     concat' :: m as -> m bs -> m cs

이제는 이기종 목록을 다음과 같이 활용합니다.

data HList ( as :: [ Type ] ) where
  HEmpty :: HList '[]
  HCons  :: a -> HList as -> HList (a ': as)

그러나 나는 이러한 선언 할 때 Concatable나는 문제가있는

instance Concatable HList '[] bs bs where
  concat' HEmpty bs = bs
instance
  ( Concatable HList as bs cs
  )
    => Concatable HList (a ': as) bs (a ': cs)
  where
    concat' (HCons head tail) bs = HCons head (concat' tail bs)

세 번째 기능 의존성을 만족시키지 않습니다. 또는 오히려 컴파일러는 우리가하지 않는다고 생각합니다. 이는 컴파일러가 두 번째 인스턴스에서 그렇다고 생각하기 때문입니다 bs ~ (a ': cs). 그리고 경우에 해당 될 수 있습니다 Concatable as (a ': cs) cs.

세 가지 종속성이 모두 충족되도록 인스턴스를 조정하려면 어떻게해야합니까?


1
중요한 문제가 될 것으로 보인다 bs cs -> as우리가 로컬이 아닌 정보를 필요로하기 때문에, bs그리고 cs여부를 결정하는 as단점 또는 전무을해야합니다. 이 정보를 나타내는 방법을 찾아야합니다. 직접 추론 할 수 없을 때이를 보장하기 위해 형식 서명에 어떤 컨텍스트를 추가합니까?
luqui

3
luqui 말한 확장하려면 : 우리가 알고있는 상상 bs하고 cs, 즉 우리가 재구성하려면, 우리가 fundep을 악용하려는 as. 결정적인 방식으로이를 수행하기 위해 단일 인스턴스에 커밋하고 해당 레시피를 따를 수있을 것으로 기대합니다. 구체적으로, 가정 bs = (Int ': bs2)cs = (Int ': cs2). 어떤 인스턴스를 선택합니까? 이 같은 가능성이 Int있는가 cs에서 온다 bs(그리고 as비어 있습니다). as대신 (비어 있지 않음)에서 왔으며 나중에 Int다시 나타날 수도 cs있습니다. 우리는 더 깊이 파고 들어야 cs하고, GHC는 그렇게하지 않을 것입니다.
chi

1
대략적으로 말하면, GHC는 인스턴스로부터 간단한 형태의 유도를 사용하여 증명할 수있는 자금을 수용 할 것입니다. 여기서, 그중 하나는 증명을 위해 일종의 이중 유도가 필요하며 컴파일러는 그렇게 멀지 않습니다.
chi

답변:


10

따라서 의견에서 알 수 있듯이 GHC는 자체적으로 파악하지 않지만 약간의 유형 수준 프로그래밍으로 도울 수 있습니다. 몇 가지를 소개하겠습니다 TypeFamilies. 이러한 모든 기능은 목록 조작을 유형 레벨로 올린 간단한 번역입니다.

-- | This will produce the suffix of `cs` without `as`
type family DropPrefix (as :: [Type]) (cs :: [Type]) where
  DropPrefix '[] cs = cs
  DropPrefix (a ': as) (a ': cs) = DropPrefix as cs

-- Similar to the logic in the question itself: list concatenation. 
type family Concat (as :: [Type]) (bs :: [Type]) where
  Concat '[] bs = bs
  Concat (head ': tail) bs = head ': Concat tail bs

-- | Naive list reversal with help of concatenation.
type family Reverse (xs :: [Type]) where
  Reverse '[] = '[]
  Reverse (x ': xs) = Concat (Reverse xs) '[x]

-- | This will produce the prefix of `cs` without `bs`
type family DropSuffix (bs :: [Type]) (cs :: [Type]) where
  DropSuffix bs cs = Reverse (DropPrefix (Reverse bs) (Reverse cs))

-- | Same definition of `HList` as in the question
data HList (as :: [Type]) where
  HEmpty :: HList '[]
  HCons :: a -> HList as -> HList (a ': as)

-- | Definition of concatenation at the value level
concatHList :: (cs ~ Concat as bs) => HList as -> HList bs -> HList cs
concatHList HEmpty bs = bs
concatHList (HCons head tail) bs = HCons head (concatHList tail bs)

이 도구를 사용하면 실제로 시간 목표를 달성 할 수 있지만 먼저 원하는 속성으로 함수를 정의합시다.

  • 과 에서 추론 cs하는 능력asbs
  • 과 에서 추론 as하는 능력bscs
  • 과 에서 추론 bs하는 능력ascs

짜잔 :

concatH ::
     (cs ~ Concat as bs, bs ~ DropPrefix as cs, as ~ DropSuffix bs cs)
  => HList as
  -> HList bs
  -> HList cs
concatH = concatHList

테스트 해보자.

foo :: HList '[Char, Bool]
foo = HCons 'a' (HCons True HEmpty)

bar :: HList '[Int]
bar = HCons (1 :: Int) HEmpty
λ> :t concatH foo bar
concatH foo bar :: HList '[Char, Bool, Int]
λ> :t concatH bar foo
concatH bar foo :: HList '[Int, Char, Bool]

그리고 마지막 목표 :

class Concatable (m :: k -> Type) (as :: k) (bs :: k) (cs :: k)
  | as bs -> cs
  , as cs -> bs
  , bs cs -> as
  where
  concat' :: m as -> m bs -> m cs

instance (cs ~ Concat as bs, bs ~ DropPrefix as cs, as ~ DropSuffix bs cs) =>
         Concatable HList as bs cs where
  concat' = concatH
λ> :t concat' HEmpty bar
concat' HEmpty bar :: HList '[Int]
λ> :t concat' foo bar
concat' foo bar :: HList '[Char, Bool, Int]
λ> :t concat' bar foo
concat' bar foo :: HList '[Int, Char, Bool]

3
잘 했어! 나는 이것이 불가능할 것으로 의심했지만 투명하고 우아하게 해결했습니다.
luqui

감사합니다, @luqui
lehins
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.