2017-02-09 1 views
12

길이가 인 n 인리스트 L이리스트 J에 인터리브되고 길이가 n + 1 인 것으로 가정하십시오. J의 각 요소에 대해 L의 이웃 중 어느 것이 더 큰지 알고 싶습니다. 다음의 기능은 길이가, 그 입력으로 L 걸리고,리스트 K를 생성 N + 1은 K의 I에게 번째 요소 J.의 I th 요소의 원하는 이웃 같은 것을유형 시스템을 사용하여 출력 길이 대 입력리스트를 점검하십시오.

aux [] prev acc = prev:acc 
aux (hd:tl) prev acc = aux tl hd ((max hd prev):acc) 

expand row = reverse (aux row 0 []) 

나는 (I 원래 OCaml로 쓴)이 함수의 결과의 길이는 입력의 길이에 1을 더한 것으로, 비공식적으로, 자신에게 증명할 수 있습니다. 하지만 나는 이 불변하는 타입 시스템을 통해 증명할 수 있다는 것에 관심이 있었기 때문에 하스켈 (나를위한 새로운 언어)에 건너 뛴 입니다.

* Could not deduce: (m1 :+: S (S m)) ~ S (m1 :+: S m) 
    from the context: n ~ S m1 
    bound by a pattern with constructor: 
       Cons :: forall a m. a -> List a m -> List a (S m), 
      in an equation for `aux' 
    at pyramid.hs:23:6-15 
    Expected type: List a (n :+: S m) 
    Actual type: List a (m1 :+: S (S m)) 
* In the expression: aux tl hd (Cons (max hd prev) acc) 
    In an equation for `aux': 
     aux (Cons hd tl) prev acc = aux tl hd (Cons (max hd prev) acc) 
* Relevant bindings include 
    acc :: List a m (bound at pyramid.hs:23:23) 
    tl :: List a m1 (bound at pyramid.hs:23:14) 
    aux :: List a n -> a -> List a m -> List a (n :+: S m) 
     (bound at pyramid.hs:22:1) 

내가가 필요한 것으로 보인다 :

{-# LANGUAGE GADTs, TypeOperators, TypeFamilies #-} 

data Z 
data S n 

type family (:+:) a b :: * 
type instance (:+:) Z n = n 
type instance (:+:) (S m) n = S (m :+: n) 

-- A List of length 'n' holding values of type 'a' 
data List a n where 
    Nil :: List a Z 
    Cons :: a -> List a m -> List a (S m) 

aux :: List a n -> a -> List a m -> List a (n :+: (S m)) 
aux Nil prev acc = Cons prev acc 
aux (Cons hd tl) prev acc = aux tl hd (Cons (max hd prev) acc) 

그러나, 마지막 줄은 다음과 같은 오류가 발생합니다 : this previous answer의 도움으로, 나는 다음과 같은까지 얻을 수 있었다 컴파일러는 (x :+: (S y)) ~ S (x :+: y)을 가르쳐야합니다. 이것이 가능한가?

또는이 유형의 시스템보다이 문제에 더 효과적인 도구가 있습니까?

+0

'x'에 대한 유도로 증명하고 아마도 어딘가에 'x'에 대한 싱글 톤을 정의하고 사용하는 것이 필요해 보입니다. 또한이 기계류는 불행히도 런타임에 지워지지 않으므로 단일 'Refl'을 생성하기 위해서만 O (n) 단계를 낭비 할 것입니다. (나는 GHC가 이것을 언젠가 O (1)에 최적화 할 수 있길 바란다 ... :) – chi

+0

@chi 이런 종류의 GHC 최적화를 여러 번 언급했는데 (나는 기억할 수있다.) 나는 그것이 존재했으면 좋겠다. 너무. 이미 알고있는 기존의 노력이 있습니까? – Alec

+0

@Alec 내 장기간의 불평과 소원 때문에 유감 스럽다. 나는 그것을 도울 수 없다. 나는 GHC 개발을 따르고 있지 않기 때문에 그것에 대한 계획이 있는지 여부에 대해서는 언급 할 수 없다. – chi

답변

8

첫째, 일부 수입 및 언어 확장 : 우리는 지금 우리가 (자신의 종류) 유형 수준 어떤 데이터를 홍보 할 수 DataKinds (or TypeInType)

{-# LANGUAGE GADTs, TypeInType, RankNTypes, TypeOperators, TypeFamilies, TypeApplications, AllowAmbiguousTypes #-} 

import Data.Type.Equality 

때문에 식 레벨 원주민 정말 자격 일반 data (도대체, 이것은 정확히입니다. 동기 부여 예제는 GHC 문서에 대한 이전 링크가 제공합니다!). List 유형으로 변경되는 사항은 없지만 (:+:)이어야합니다. 유형의 가족 (현재는 종류가 Nat 이상)이어야합니다.

-- A natural number type (that can be promoted to the type level) 
data Nat = Z | S Nat 

-- A List of length 'n' holding values of type 'a' 
data List a n where 
    Nil :: List a Z 
    Cons :: a -> List a m -> List a (S m) 

type family (+) (a :: Nat) (b :: Nat) :: Nat where 
    Z + n = n 
    S m + n = S (m + n) 

이제 증거가 aux을 위해 일하게하기 위해, 자연 번호를 singleton types을 정의하는 데 유용합니다.

-- A singleton type for `Nat` 
data SNat n where 
    SZero :: SNat Z 
    SSucc :: SNat n -> SNat (S n) 

-- Utility for taking the predecessor of an `SNat` 
sub1 :: SNat (S n) -> SNat n 
sub1 (SSucc x) = x 

-- Find the size of a list 
size :: List a n -> SNat n 
size Nil = SZero 
size (Cons _ xs) = SSucc (size xs) 

이제 우리는 몇 가지 것을 증명하기 시작했습니다. Data.Type.Equality에서 a :~: ba ~ b이라는 증명을 나타냅니다. 우리는 산술에 대해 간단한 것을 증명할 필요가 있습니다.

-- Proof that  n + (S m) == S (n + m) 
plusSucc :: SNat n -> SNat m -> (n + S m) :~: S (n + m) 
plusSucc SZero _ = Refl 
plusSucc (SSucc n) m = gcastWith (plusSucc n m) Refl 

마지막으로, 우리는 aux이 증거를 사용하는 gcastWith를 사용할 수 있습니다. 오, 너는 Ord a 제약이 없다.:)

aux :: Ord a => List a n -> a -> List a m -> List a (n + S m) 
aux Nil prev acc = Cons prev acc 
aux (Cons hd tl) prev acc = gcastWith (plusSucc (size tl) (SSucc (size acc))) 
             aux tl hd (Cons (max hd prev) acc) 

-- append to a list 
(|>) :: List a n -> a -> List a (S n) 
Nil |> y = Cons y Nil 
(Cons x xs) |> y = Cons x (xs |> y) 

-- reverse 'List' 
rev :: List a n -> List a n 
rev Nil = Nil 
rev (Cons x xs) = rev xs |> x 

이 귀하의 질문에 답을 알려줘 - 이런 종류의 물건을 시작하는 것은 새 물건을 많이 포함한다.

+0

감사합니다. 이것은 확실히 내가 찾고 있었던 것입니다. 그러나, 당신이 언급했듯이, 여기서 무슨 일이 벌어지고 있는지 완전히 이해하기 전에 약간의 독서를해야 할 것입니다. –

+0

@Levi Roth,이 기능을 정의 할 증거는 필요하지 않습니다. [this] (https://www.reddit.com/r/haskell/comments/2tmxsv/a_type_safe_reverse_or_some_hasochism/) 게시물을 참조하십시오. – user3237465

+0

@ user3237465 unsafeCoerce를 사용하여 수동으로 교정본을 무시할 것을 제안하십니까? – Alec