2014-10-10 10 views
12

Data.Typeable ile çalışıyorum ve özellikle belirli türde bir tür üretebilmek istiyorum (örneğin *). İşteHaskell Tür Tip Oluşturucu almak mümkün mü?

let maybeType = typeRep (Proxy :: Proxy Maybe) 
let maybeCon = fst (splitTyConApp maybeType) 
let badType = mkTyConApp maybeCon [maybeType] 

badType tip temsili Belki Belki bir anlamda ise şöyledir: İçine çalıştırıyorum sorun TypeRep bize (ghc 7.8 sürümüyle çalışan) aşağıdakileri yapmanız olanak sağlamasıdır herhangi Kind geçerli bir türü:

> :k Maybe (Maybe) 

<interactive>:1:8: 
    Expecting one more argument to ‘Maybe’ 
    The first argument of ‘Maybe’ should have kind ‘*’, 
     but ‘Maybe’ has kind ‘* -> *’ 
    In a type in a GHCi command: Maybe (Maybe) 

Ben tür düzeyinde bu zorlama aramıyorum ama zamanında böyle tipleri inşa önlemek için yeterince akıllı bir program yazabilmek istiyorum. Bunu TypeRep ile veri düzeyi şartları ile yapabilirim. İdeal olarak, ben (muhtemelen gerçekten kindOf (Proxy :: Proxy Int) = Star) ve kindOf Maybe = KFun Star Star, böylece benim TypeRep değerini "tür-kontrol" olabilir

data KindRep = Star | KFun KindRep KindRep 

gibi bir şey var ve bir fonksiyonu kindOf Int = Star ile kindOf olurdu.

Bunu el ile Typeable gibi çok noktalı bir yazım hatası ile yapabileceğimi düşünüyorum, ancak her şey için kendi örneklerimi yazmak zorunda kalmamayı tercih ediyorum. Ayrıca, GHC 7.6'ya geri dönmemeyi ve farklı tipte Tip türleri için ayrı tip sınıfları olduğunu kullanmayı tercih ederim. Bu bilgiyi GHC'den alan yöntemlere açığım.

+0

'typeOf1' ve' Typeable1' (ve arkadaşlar) hala 'Data.Typeable' öğesinden dışa aktarılıyor ... bunlar 7.8'de kullanılabilir. –

cevap

12

Bu tür bir tür elde edebiliriz, ancak GHC'de (bu örnekte) sorgulanabilir UndecidableInstances ve AllowAmbiguousTypes'u aşan bir dizi dil uzantısını atmamız gerekir.

{-# LANGUAGE KindSignatures #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE PolyKinds #-} 
{-# LANGUAGE ScopedTypeVariables #-} 
{-# LANGUAGE UndecidableInstances #-} 
{-# LANGUAGE AllowAmbiguousTypes #-} 

import Data.Proxy 

bir KindRep

data KindRep = Star | KFun KindRep KindRep 

için tanımını kullanarak kimin tür tür

class Kindable x where 
    kindOf :: p x -> KindRep 

Bunun için ilk derece kolaydır, her şeyi tespit edilebilir Kindable şeylerin sınıfını tanımlamak *, Kindable:

instance Kindable (a :: *) where 
    kindOf _ = Star 

Daha iyi türdeki türlerin alınması zordur. Tartışmanın türünü ve bir argümana başvurmanın sonucunu bulabilirsek, onun türünü anlayabileceğimizi söyleyeceğiz. Ne yazık ki, bir argümanı olmadığı için, argümanının ne tür olacağını bilmiyoruz; Bu yüzden AllowAmbiguousTypes'a ihtiyacımız var.

instance (Kindable a, Kindable (f a)) => Kindable f where 
    kindOf _ = KFun (kindOf (Proxy :: Proxy a)) (kindOf (Proxy :: Proxy (f a))) 

Kombine, bu tanımlar bizi Hemen neyse sonuçlanır Proxy

kindOf (Proxy :: Proxy Proxy) 

gibi polykinded tip türünü belirlemek kalkmayın

kindOf (Proxy :: Proxy Int) = Star 
kindOf (Proxy :: Proxy Maybe) = KFun Star Star 
kindOf (Proxy :: Proxy (,)) = KFun Star (KFun Star Star) 
kindOf (Proxy :: Proxy StateT) = KFun Star (KFun (KFun Star Star) (KFun Star Star)) 

gibi şeyler yazmak için izin Bir derleyici hatası sadece sınırlı bir süre içinde.

+0

FYI, çoğu Haskell masters 'UndecidableInstances' makul bir şey düşünün. AllowAmbiguousTypes'ın gölgeli tarafta biraz olabileceğini hayal ediyorum - bu çıkarımı biraz lapaçık yapar mı? – dfeuer