2013-10-31 8 views
5

나는 a GADT walkthrough을 통해 읽고 있었고 연습 중 하나에서 멈추었습니다. 주어진 자료 구조는 다음과 같습니다GADT를 사용하는 "안전한 목록"을위한 테일 기능

{-# LANGUAGE GADTs, EmptyDataDecls, KindSignatures #-} 
data NotSafe 
data Safe 
data MarkedList :: * -> * -> * where 
    Nil :: MarkedList t NotSafe 
    Cons :: a -> MarkedList a b -> MarkedList a c 

운동은 safeTail 기능을 구현하는 것입니다.

safeTail (Cons 'c' (Cons 'a' (Cons 't' Nil))) == Cons 'a' (Cons 't' Nil) 
safeTail (Cons 'x' Nil)      == Nil 
safeTail Nil -- type error (not runtime!) 

가 (실제로 ==을 정의하지 않았다, 그러나 희망이 무슨 뜻인지 분명)

이이

을 수행 할 수 있습니다 : 나는 서곡에 tail 기능과 비슷한 역할을하고 싶습니다? 나는 타입이 심지어 무엇이 될지 전혀 모른다. 아마 safeTail :: MarkedList a Safe -> MarkedList a NotSafe?

+0

참고. 간접적으로 저를 "버그"로 안내해 주셔서 감사합니다. – duplode

+0

당신이 받아 들인 것이 흥미 롭다고하더라도 당신이 틀린 대답을 받아 들였다고 생각합니다. 이 연습에서는 데이터 유형을 변경하도록 요청하지 않습니다. –

답변

7

당신이 유형의 구조를 조금 변경하는 경우 safeTail을 구현할 수 :

{-# LANGUAGE GADTs, EmptyDataDecls, KindSignatures #-} 

data Safe a 
data NotSafe 

data MarkedList :: * -> * -> * where 
    Nil :: MarkedList t NotSafe 
    Cons :: a -> MarkedList a b -> MarkedList a (Safe b) 

safeHead :: MarkedList a (Safe b) -> a 
safeHead (Cons h _) = h 

safeTail :: MarkedList a (Safe b) -> MarkedList a b 
safeTail (Cons _ t) = t 

원래 safeTail :: MarkedList a Safe -> MarkedList a b의 문제는 b 어떤 유형이 될 수 있다는 것입니다 - 반드시 같은 종류 그의 꼬리 목록에으로 표시됩니다. 이것은 리턴 타입이 safeTail 인 것을 허용하는 타입 레벨에리스트 구조를 적절히 제한함으로써 여기에서 고쳐졌습니다.

+5

참고 : 여기의 인덱스는 정확히 자연수 형식이므로 길이의 인코딩과 동일합니다. –

+4

물론, 이렇게 할 때'NotSafe'와'Safe'를'Zero'와'Succ'로 이름을 바꿀 수도 있습니다. :-)리스트의 타입은 length가 0인지 아닌지를 알려줍니다. – shachaf

+0

매우 깔끔한! 나는 그 'safeTail $ safeTail $ Cons'c '$ Cons'a '$ Cons't 'Nil'도 여기서 일한다. 질문에 제안 된 유형 서명이 허용되지 않았을 것입니다. – Snowball

4

예, 가능합니다. 그 트릭은 존재 적으로 정량화 된 포함 목록을 알려진 유형의 목록으로 바꾸는 것입니다. 구체적으로는 NotSafe입니다.

unsafe :: MarkedList a b -> MarkedList a NotSafe 
unsafe Nil = Nil 
unsafe (Cons a b) = Cons a b 

이제 우리는 안전하게 꼬리를 취할 수 있습니다

safeTail :: MarkedList a Safe -> MarkedList a NotSafe 
safeTail (Cons a b) = unsafe b 

또한이 패턴 일치가 완료됩니다. -fwarn-incomplete-patterns에서 경고를받지 못하며 Nil 절을 추가하려고하면 오류가 발생합니다. 의는 Show 인스턴스를 도출, StandaloneDeriving 켜고 귀하의 샘플을 테스트 해보자 5 분전까지 장에서 링크 된 솔루션은 분명히 잘못했다

*Main> safeTail (Cons 'c' (Cons 'a' (Cons 't' Nil))) 
Cons 'a' (Cons 't' Nil) 
*Main> safeTail (Cons 'x' Nil) 
Nil 
*Main> safeTail Nil 

<interactive>:10:10: 
    Couldn't match type `NotSafe' with `Safe' 
    Expected type: MarkedList a0 Safe 
     Actual type: MarkedList a0 NotSafe 
    In the first argument of `safeTail', namely `Nil' 
    In the expression: safeTail Nil 
    In an equation for `it': it = safeTail Nil 
+1

당신의 함수는'safeTail $ safeTail'을 쓸모없는리스트에서 가져올 수 없습니다. 그래도 질문에 답을하고 대답은 safeTail을 구현하라고 요청하지만 데이터 유형을 변경하도록 초대하지 않았기 때문에 허용 된 대답은 아닙니다. 사실 나는 그 이유 때문에 그것이 일종의 진절머리 나는 운동이라고 생각합니다. –