2010-02-19 17 views
15

Experimentando con tipos existenciales. Parece ser una gran manera de obtener flexibilidad de tipo.¿Cómo descomprimir un tipo existencial haskell?

Estoy solucionando un problema con unboxing de tipo existencial después de que lo envolví. Mi código de la siguiente manera:

{-# LANGUAGE ExistentialQuantification #-} 

class Eq a => Blurb a 
data BlurbBox = forall a . Blurb a => BlurbBox a 

data Greek = Alpha | Beta deriving Eq 
instance Blurb Greek 

data English = Ay | Bee deriving Eq 
instance Blurb English 

box1 :: BlurbBox 
box1 = BlurbBox Alpha 

box2 :: BlurbBox 
box2 = BlurbBox Ay 

main = do 
    case box1 of 
     BlurbBox Alpha -> putStrLn "Alpha" 
     BlurbBox Beta -> putStrLn "Beta" 
     BlurbBox Ay -> putStrLn "Ay" 
     BlurbBox Bee -> putStrLn "Bee" 

Este código se compila hasta principal, luego se queja sobre el tipo de BlurbBox Alfa. ¿Cómo hago para desempaquetar/desempaquetar un tipo existencial?

Respuesta

14

De hecho, los tipos existenciales no se puede descomprimir, porque toda su punto es que el código esperando un tipo existencial debe trabajar absolutamente de la misma manera (en el sentido del polimorfismo paramétrico), independientemente de con que escriba la exacta la variable de tipo existencial fue instanciada.

Se puede entender que un mejor entendiendo que

data BlurbBox = forall a . Blurb a => BlurbBox a 

se traduce a

type BlurbBox = forall b . (forall a . Blurb a => a -> b) -> b 

que es, BlurbBox es algo que, dada una función polimórfica que funcione para absolutamente todos Blurbs, se puede utilizado para producir el resultado de aplicar esa función a alguna propaganda (desconocida).

Por lo tanto, de forma similar a como no puede escribir una función de tipo f :: a -> Int y tiene f String = 5 yf Bool = 3, no puede enviar en el tipo de 'a' en un BlurbBox.

Puede echar un vistazo al capítulo en TAPL sobre tipos existenciales. Describe la traducción que he proporcionado.

+0

¿tiene un enlace para saber cómo y dónde ocurre esta traducción? BlurbBox (el constructor) tiene el tipo 'forall a. Blurb a => a -> BlurbBox 'pero el tipo en sí mismo (en general) es isomorfo a ...? – nicolas

+0

que puede ayudar. https://mail.haskell.org/pipermail/haskell-cafe/2010-May/078254.html el ejercicio 23.4.8 de TAPL y el capítulo 24.3 son útiles también – nicolas

4

Por lo que sé, no puedes hacer eso. El objetivo de los tipos existenciales es ocultar un tipo, para que pueda acceder a todas las "instancias" de manera uniforme (algo así como el envío dinámico de métodos de subclase en Java y otros lenguajes orientados a objetos).

Así, en su ejemplo, su "interfaz" es BlurbBox y lo utilizaría para aplicar algún método de manera uniforme a diferentes BlurbBoxes, sin preocuparse por lo que el tipo interno a es (por ejemplo, si Blurb subclases Show, entonces usted puede tener a [BlurbBox] e imprima cada elemento de la lista sin tener que conocer el tipo interno exacto de cada BlurbBox en la lista).

11

No puede * especializar un tipo después de haberlo escondido. Agregue alguna restricción o método al Blurb si necesita una operación como esta.

-- choose one 
class (Eq a, Show a) => Blurb a where 
    printBlurb :: a -> IO() 
instance Blurb Greek where 
    printBlurb Alpha = putStrLn "Alpha" 
... 

class (Eq a, Show a) => Blurb a 
data Greek deriving (Eq, Show) 
... 

data BlurbBox = forall a. (Blurb a, Show a) => BlurbBox a 
data Greek deriving (Eq, Show) 
... 

* Yo recomendaría mucho contra esto, pero si realmente quería y hellip;

{-# LANGUAGE DeriveDataTypeable #-} 
import Data.Dynamic 

data Greek = Alpha | Beta deriving (Eq, Typeable) 
data English = Ay | Bee deriving (Eq, Typeable) 

box1 :: Dynamic 
box1 = toDyn Alpha 

box2 :: Dynamic 
box2 = toDyn Ay 

main = do 
    case fromDynamic box1 of 
     Just Alpha -> putStrLn "Alpha" 
     Just Beta -> putStrLn "Beta" 
     Nothing -> case fromDynamic box1 of 
     Just Ay -> putStrLn "Ay" 
     Just Bee -> putStrLn "Bee" 
+0

¿Podría explicarnos mejor sobre su segunda versión con 'Dynamic's, why * against *? – wowofbob