2011-11-06 23 views
6

İşte bu var tip güvenliğini almak için: BuradaDeğişkin liste yapıcısı, nasıl doğru türe varsayılan ve

{-# LANGUAGE MultiParamTypeClasses 
      , FlexibleInstances #-} 

class ListResultMult r a where 
    lstM :: a -> [a] -> r 

listM :: ListResultMult r a => a -> r 
listM a = lstM a [] 


instance ListResultMult r a => ListResultMult (a -> r) a where 
    lstM a as x = lstM x $ a:as 

instance ListResultMult [a] a where 
    lstM a as = reverse $ a:as 

şekilde çalışır: o

başarısız nasıl

İşte
> listM 'a' 'b' 'c' :: String 
"abc" 
> putStrLn $ listM 'a' 'b' 'c' 
abc 
> listM (1::Int) (2::Int) :: [Int] 
[1,2] 

var printf ile

> sum $ listM 1 2 
No instance for (ListResultMult (a2 -> [a0]) a1) ... 
> listM 1 :: [Int] 
No instance for (ListResultMult [Int] a0) ... 

Kontrast:

instance Show a => ListResultMult (IO()) a where 
    lstM a as = print . reverse $ a:as 

> listM "foo" "bar" -- boo 
No instance for (ListResult t0 [Char]) ... 
> printf "%s %s" "foo" "bar" 
foo bar 
> listM "foo" "bar" :: IO() -- yay 
["foo","bar"] 

Tip güvensizlik:

  • Tip Güvenliği: Yani burada

    > :t listM 2 "foo" 
    Some weird type is actually inferred 
    

    yapmak istediğim şey bu. ListResultMult r a => ListResultMult (a -> r) a ve ListResultMult [a] a'u tanımladığımda, yalnızca homojen listeler oluşturmanıza izin vermediğinizi ve bunu yapmadığınız zaman bir tür hatayı farkettiğinizi düşündüm. Neden yapmadı?

  • Hata giderme. listM 1 :: [Int] ile garipliğin neler olduğu hakkında hiçbir fikrim yok. N'aber?

cevap

6

Tipi fonksiyonları bu sorun için sadece bilet gibi görünüyor. Burada örnek bir dosya var:

İşte
{-# LANGUAGE TypeFamilies #-} 

class ListResultMult r where 
    type Elem r 
    lstM :: Elem r -> [Elem r] -> r 

listM a = lstM a [] 

instance (ListResultMult r, Elem r ~ a) => ListResultMult (a -> r) where 
    type Elem (a -> r) = a 
    lstM a as x = lstM x (a:as) 

instance ListResultMult [a] where 
    type Elem [a] = a 
    lstM a as = reverse (a:as) 

GHCi daki örnekler:

*Main> listM 'a' 'b' 'c' :: String 
"abc" 
*Main> putStrLn $ listM 'a' 'b' 'c' 
abc 
*Main> listM 1 2 :: [Int] 
[1,2] 
*Main> sum $ listM 1 2 
3 
*Main> listM 1 :: [Int] 
[1] 
*Main> :t listM 'a' True 

<interactive>:1:7: 
    Couldn't match type `Bool' with `Char' 
    In the first argument of `listM', namely 'a' 
    In the expression: listM 'a' True 
*Main> :t listM 2 "foo" 

<interactive>:1:7: 
    No instance for (Num [Char]) 
     arising from the literal `2' 
    Possible fix: add an instance declaration for (Num [Char]) 
    In the first argument of `listM', namely `2' 
    In the expression: listM 2 "foo" 
+0

Tip emniyet * ve * aklı başında varsaymak! Bu, soruyu mükemmel bir şekilde yanıtlamasının yanı sıra tesadüfen diğer sorumu da yanıtladı (http://stackoverflow.com/questions/8031320). :) –

İlgili konular