2011-11-06 19 views
6

Esto es lo que tengo:lista variadic constructor, cómo por defecto para el tipo correcto y obtener la seguridad de tipos

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

Así es como funciona:

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

Así es como falla

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

contraste 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 inseguridad:

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

Así que esto es lo que quiero hacer:

  • Tipo de seguridad. Pensé que cuando definiera ListResultMult r a => ListResultMult (a -> r) a y ListResultMult [a] a, solo le permitiría crear listas homogéneas, y notaría un error tipográfico cuando no lo haga. ¿Por qué no?
  • Defecto. No tengo ni idea de qué está sucediendo la rareza con listM 1 :: [Int]. ¿Qué pasa?

Respuesta

6

Las funciones de tipo parecen ser solo el boleto para este problema. Aquí está un ejemplo de archivo:

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

Éstos son sus ejemplos en ghci: seguridad

*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 * y * cuerdo morosos! Esto respondió la pregunta perfectamente, así como casualmente respondiendo [mi otra pregunta] (http://stackoverflow.com/questions/8031320). :) –

Cuestiones relacionadas