2012-07-29 13 views
6

bir Enum türü ile ilişkili Ints listesini oluşturun:Ben enumerable olduğundan hem de sınırlanmış bir türdeki tüm değerlerini sıralar bir yardımcı fonksiyonu var

enumerate :: (Enum a, Bounded a) => [a] 
enumerate = [minBound .. maxBound] 

ve tamsayılar için haritalama enumerable türlerini içeren bir veri türü : vals tüm olası enumerable değerleri temsil tamsayılar listesidir

data Attribute a = Attribute { test :: a -> Int 
          , vals :: [Int] 
          , name :: String } 

. Örneğin, eğer

data Foo = Zero | One | Two deriving (Enum,Bounded) 

sonra vals [0,1,2] olacağını vardı.

Ben sadece bir enumerable tip bir a eşleştiren bir fonksiyon ve bir isim verilmiş, programlama yoluyla bu özellikleri oluşturmak isterler. Böyle bir şey: tip imzasında b ile enumerate çağrısını bağlamanın bir yolu yoktur çünkü

attribute :: (Enum b, Bounded b) => (a -> b) -> String -> Attribute a 
attribute f str = Attribute (fromEnum . f) vs str 
    where 
    vs = map fromEnum enumerate 

Bu, typecheck etmez.

vs = map fromEnum $ enumerate :: [b] 

ama bu derleme ya gelmez - derleyici o bb1 yeniden adlandırır: Ben bunu yapabileceğimi düşündüm.

attribute :: (Enum b, Bounded b, b ~ c) => {- ... -} 
vs = map fromEnum $ enumerate :: (Enum c,Bounded c) => [c] 

ama yine cc1 yeniden adlandırılır: Ben GADTs uzantısını kullanarak, akıllı olmaya çalıştım.

ben Attribute türü (I b potansiyel farklı değerlere sahip nitelikler listelerini depolamak istediğiniz başlıca nedeni parametre olarak b türünü içerecek şekilde istemiyorum - testa -> Int tip vardır ve vals[Int] tip vardır bu yüzden). ben bunu yapmak ne istiyor, böylece

nasıl bu kodu yazabilirim?

cevap

6

tip değişkenleri ile sorun sadece tip imzasında bağlı olmasıdır. Tanım içindeki tür değişkenlerinin kullanımı, yeni, yeni tip değişkeni ifade eder (tip imzasında olduğu gibi aynı ada sahip olsa bile).

İmzadaki tip değişkenlerine başvurmanın iki yolu vardır: ScopedTypeVariables uzantısı ve asTypeOf. ScopedTypeVariables açıkça forall ile bağlı bir tip değişken ile

dolayısıyla da tanımı mevcuttur: biz bir ifade sağlayabilirseniz

asTypeOf :: a -> a -> a 
asTypeOf = const 

:

attribute :: forall a b. (Enum b, Bounded b) => 
      (a -> b) -> String -> Attribute a 
attribute f str = Attribute (fromEnum . f) vs str 
    where 
    vs = map fromEnum (enumerate :: [b]) 

başka bir yol olarak tanımlanan işlev asTypeOf içerir [b] tipinin ikinci parametreye girilmesiyle, birleştirme, ilk parametrenin de [b] tipine sahip olduğundan emin olacaktır.Biz f :: a -> b ve f undefined :: b ettiğinden, yazabiliriz:

attribute :: (Enum b, Bounded b) => (a -> b) -> String -> Attribute a 
attribute f str = Attribute (fromEnum . f) vs str 
    where 
    vs = map fromEnum (enumerate `asTypeOf` [f undefined]) 
+0

Dürbünlü Tipi Değişkenler perfecly çalışıyor, teşekkürler! –

+0

Ayrıca, bu undefined''i ilk kez kullanmışken faydalı bir iş yapmak için kullanılır. –

+0

@ChrisTaylor: Tabi ki 'const' gibi farklı bir uzmanlık kullanabilirsin, örneğin: asTypeOf2 :: [b] -> (a -> b) -> [b] 've sonra da 'numaralandır' \\ asTypeOf2 yazabilirsiniz \ 'f', ama muhtemelen çabaya değmez. – Vitus

İlgili konular