2011-11-06 14 views
6

Ecco quello che ho:variadic lista del costruttore, come per default il tipo corretto e ottenere la sicurezza di tipo

{-# 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 

Ecco come funziona:

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

Ecco come riesce

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

contrasto con printf:

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"] 

Tipo insicurezza:

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

Quindi, ecco cosa voglio fare:

  • tipo di sicurezza. Ho pensato che quando ho definito ListResultMult r a => ListResultMult (a -> r) a e ListResultMult [a] a, ti avrei permesso solo di creare liste omogenee e di notare un errore di tipo quando non lo fai. Perché no?
  • Impostazione predefinita. Non ho idea di cosa sia la stranezza con listM 1 :: [Int]. Che succede?

risposta

6

Le funzioni di tipo sembrano solo il ticket per questo problema. Ecco un esempio di file:

{-# 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) 

Ecco i vostri esempi in ghci: sicurezza

*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

Tipo * e * sano inadempiente! Questo ha risposto alla domanda perfettamente, così come per coincidenza, rispondendo [la mia altra domanda] (http://stackoverflow.com/questions/8031320). :) –

Problemi correlati