2010-11-13 16 views
5

Kullanılacak veri türünü belirten bazı verileri okumak istiyorum. ÖrneğinKullanılacak veri türünü belirten girişi okuma ve temsil etme

, en bunlar gibi kullanıcı girişi olabilir orada varsayalım:

integer pair 1 2 
integer triple 1 2 3 
real pair 1 2 
real triple 1 2 3 

ve onu temsil edecek bir veri türü vardır:

data (MValue a) => T a = TP (Pair a) | TT (Triple a) 
    deriving (Show, Eq) 

data Pair a = Pair a a deriving (Show, Eq) 
data Triple a = Triple a a a deriving (Show, Eq) 

izin değer türleri ait zorunda MValue sınıfı:

class (Num a, Read a) => MValue a where 
    typename :: a -> String 
    readval :: [String] -> Maybe a 

instance MValue Int where 
    typename _ = "integer" 
    readval [s] = maybeRead s 
    readval _ = Nothing 

instance MValue Double where 
    typename _ = "real" 
    readval [s] = maybeRead s 
    readval _ = Nothing 

maybeRead s = 
    case reads s of 
    [(x,_)] -> Just x 
    _  -> Nothing 

kolaycaiçin okuyucuları yazabilirler ve Triple s:

readPair (w1:w2:[]) = Pair <$> maybeRead w1 <*> maybeRead w2 
readTriple (w1:w2:w3:[]) = Triple <$> maybeRead w1 <*> maybeRead w2 <*> maybeRead w3 

Sorun tüm T a tip için polimorfik okuyucu yazıyorsunuz nasıl geçerli:?

istediğim:

  1. tipi a arayan tarafından seçilir. Kullanıcının girişi a ile uyumlu değilse,
  2. readT, Nothing ürününü üretmelidir. Giriş geçerliyse
  3. readT, Just (T a) ürününü üretmelidir.
  4. Sayılar, girdiye bağlı olarak tamsayı olarak veya çift olarak okunmalıdır.

Saf bir uygulama

readT :: (MValue a, Read a) => String -> Maybe (T a) 
readT s = 
    case words s of 
    (tp:frm:rest) -> 
     if tp /= typename (undefined :: a) 
      then Nothing 
      else case frm of 
      "pair" -> TP <$> readPair rest 
      "triple" -> TT <$> readTriple rest 
      _ -> Nothing 
    _ -> Nothing 

hattı if tp /= typename (undefined :: a) bir hata veriyor:

rd.hs:45:17: 
    Ambiguous type variable `a' in the constraint: 
     `MValue a' arising from a use of `typename' at rd.hs:45:17-41 
    Probable fix: add a type signature that fixes these type variable(s) 
Failed, modules loaded: none. 

hata bu çeki kaldırmak, ancak nasıl doğrulanabilirse uzağa giderse kullanıcı girişi arayan tarafından seçilen veri türü ile uyumludur? Bir çözüm ayrı readTInt ve sahip olabilir, ancakgibi aynı şekilde polimorfik olarak çalışmak için aynı readT olmasını isterim.

cevap

5

Sorun, a'un undefined :: a'daki a ile aynı olmaması, readT imzasıdır. GHC'de "ScopedTypeVariables" olarak adlandırılan bir dil uzantısı var. Bir daha taşınabilir düzeltme örneğin, açıkça birbirine türlerini bağlamak için biraz ekstra kod tanıtmak olacaktır: Bu kod çok hızlı ve kirli değişikliktir

readT :: (MValue a, Read a) => String -> Maybe (T a) 
readT s = result 
    where 
    result = 
     case words s of 
     (tp:frm:rest) -> 
      if tp /= typename ((const :: a -> Maybe (T a) -> a) undefined result) 
       then Nothing 
       else case frm of 
       "pair" -> TP <$> readPair rest 
       "triple" -> TT <$> readTriple rest 
       _ -> Nothing 
     _ -> Nothing 

ve ben Yapılabilecek değişiklikler değilim Daha zarif, ama bu işe yaramalı.

+0

Teşekkür ederiz. Bu çalışıyor. Undefined 'ın bir argümanı olarak' sonuç 'trick'i' Belki (T a) -> a' beklenmedik. – sastanin

+1

Aslında, "result" ve "undefined" ifadeleri her ikisi de const :: a -> Belki (T a) -> a 'değişkenleridir; bu da, türlerini" const "üzerindeki açık tip imzasıyla ilişkili olarak ilişkili olmaya zorlar. '. Ama evet, '(undefined :: Belki (T a) -> a) sonuç' da çalışırdı. – mokus