良く型付けされたtake関数
{-# LANGUAGE GADTs #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE MultiParamTypeClasses , ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts , TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} data Zero = Zero data Succ a where Succ :: (Nat a,NimusLemma a) => a -> Succ a class Nat a where split :: (Nat a,Nat b,NimusLemma b) => a -> List e b -> (List e a,List e (Nimus b a)) instance Nat Zero where split Zero (b :: List e b) = (Nil,b') where b' :: List e (Nimus b Zero) b' = convList b (Symm lemma) instance (Nat a) => Nat (Succ a) where split (Succ a :: Succ a) (Cons b c :: List e b) = goal where (f :: List e a,s :: List e (Nimus (Pred b) a)) = split a c f' :: List e (Succ a) f' = Cons b f p :: Id a (Nimus a Zero) p = Symm $ lemma p' :: Id (Nimus (Pred b) a) (Nimus b (Succ a)) p' = proof (length' (Cons b c) :: b) (a :: a) p'' ::List e (Nimus b (Succ a)) p'' = convList s p' goal :: (List e (Succ a),List e (Nimus b (Succ a))) goal = (f',p'') type family Nimus a b type instance Nimus Zero b = Zero type instance Nimus (Succ a) Zero = (Succ a) type instance Nimus (Succ a) (Succ b) = Nimus a b type family Pred a type instance Pred Zero = Zero type instance Pred (Succ a) = a data Id :: * -> * -> * where Refl :: Id a a Symm :: (Id a b) -> (Id b a) Trans :: (Id a b) -> (Id b c) -> Id a c MapId :: Id a b -> Id (f a) (f b) convList :: List e a -> Id a b -> List e b convList (list :: List e a) (eq :: Id a b) = goal where p :: Id (List e a) (List e b) p = MapId eq goal :: List e b goal = conv list p conv :: a -> Id a b -> b conv a Refl = a class (Nat a) => NimusLemma a where lemma :: Id (Nimus a Zero) a instance NimusLemma Zero where lemma = Refl instance (Nat a) => NimusLemma (Succ a) where lemma = Refl class (Nat a,Nat b) => NimusProof a b where proof :: a -> b -> Id (Nimus (Pred a) b) (Nimus a (Succ b)) instance (Nat a) => NimusProof Zero a where proof _ _ = Refl instance (Nat a,Nat b) => NimusProof (Succ a) b where proof _ _ = Refl data List a n where Nil :: List a Zero Cons :: (Nat n,NimusLemma n) => a -> List a n -> List a (Succ n) instance (Show a) => Show (List a n) where show Nil = "[]" show (Cons x xs) = show x ++ "," ++ show xs length' :: List a n -> n length' Nil = Zero length' (Cons x xs) = Succ (length' xs) -- 単にこれが書きたかった!! take' :: (Nat n,Nat l,NimusLemma n) => l -> List a n -> List a l take' l list = fst $ split l list -- 一応使ってみる intlist :: List Int (Succ (Succ (Succ (Succ Zero)))) intlist = Cons 0 (Cons 1 (Cons 2 (Cons 3 Nil))) taked :: List Int (Succ (Succ (Succ Zero))) taked = take' (Succ (Succ (Succ Zero))) intlist
超力業。で、力業に見えなくも無い程度にはすんなり収まった気配を見せているがクラスコンテキストがぐちゃぐちゃになってるのと、Natにsplitって一体全体みたいな感じに成っていて、まぁsplitがまずかった!!
Nimusくんまじやばいで・・・。
あと途中こんなコード断片が出て来て
convList :: (Nat a,Nat b,NimusProof a b) => List e (Nimus (Pred a) b) -> List e (Nimus a (Succ b)) convList (list :: List e (Nimus (Pred a) b)) = undefined
エラーメッセージが
Pattern signature must exactly match: List e (Nimus (Pred a) b) In the pattern: list :: List e (Nimus (Pred a) b) In the definition of `convList': convList (list :: List e (Nimus (Pred a) b)) = undefined
良く分からんなーみたいな。
証明はforallに対して書けるのですが、type familyが型変数を持って手放してくれない場合はそれは型変数ではなくてrigitな型で実型が隠れているみたいな感じなので、どうしてもScopedTypeVariableを使って引っ張りださないといけない => でも書けない => なのでproofには第一引数と第二引数を与えてそれにあう証明にしちゃう、という感じにしています。
丸一日かかった。頭悪過ぎる。
例によって使わないオプションも存在。