2012-01-23 14 views
6

Este es un ejemplo mínimo tomado de Reflection-0.5.Haskell: ¿Por qué este tipo de verificación?

{-# LANGUAGE Rank2Types, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-} 
{-# OPTIONS_GHC -fno-cse -fno-full-laziness -fno-float-in #-} 

import Control.Applicative 
import Data.Proxy 

newtype Zero = Zero Zero deriving (Show) 

class ReifiesNum s where 
    reflectNum :: Num a => proxy s -> a 

instance ReifiesNum Zero where 
    reflectNum = pure 0 

En GHCi, me sale el siguiente:

>:t Zero 
Zero :: Zero -> Zero 

Esto tiene sentido: lo que estoy pidiendo el tipo de constructor que tiene un cero y devuelve un cero.

>:t reflectNum 
reflectNum :: (ReifiesNum s, Num a) => proxy s -> a 

Tiene sentido que podría escribir algo así como

>let x = Just (undefined::Zero) 
>reflectNum x 

porque el tipo Justo cero coincide con las variables de tipo de proxy 's'.

Por último, la parte confusa:

>:t (reflectNum Zero) 
(reflectNum Zero) :: Num a => a 

No entiendo cómo el tipo del constructor Cero Cero :: -> Cero aparentemente coincide con las variables de tipo de proxy 's', pero al parecer lo hace debido a que la tipo de (reflectNum Zero) es solo 'a'.

Agradecería ayuda para entender este ejemplo, y los enlaces a los conceptos relevantes serían muy apreciados.

Gracias

Respuesta

11

Es sólo la sintaxis infija de la flecha función de tirar que fuera. Primero, he aquí un ejemplo con un caso fácil de entender: Maybe Int. Para hacer que se acople proxy s, acabamos de fijar:

proxy = Maybe 
s = Int 

Ahora vamos a suponer a -> b está escrito en lugar Fun a b, y así Zero tiene por tipo Fun Zero Zero (es decir (Fun Zero) Zero). Para hacer que se acople proxy s, nos propusimos:

proxy = Fun Zero 
s = Zero 

En realidad, es proxy(->) Zero, y así es proxy s((->) Zero) Zero ≡ ≡ (->) Zero ZeroZero -> Zero.

+0

¿Por qué "(->) Zero" es un tipo válido? No puedo imaginar cómo podría escribir algo como "> dejar x = [algo] :: ((->) cero"). Espero que tenga sentido. ¡Gracias por la respuesta! – crockeea

+3

@Eric '(->) Zero' no es un tipo válido, es un * constructor de tipo *, que debe aplicarse a otro tipo para formar un tipo concreto. Lo mismo es cierto de 'Maybe'; no hay valores de tipo 'Maybe', pero hay valores de tipo' Maybe Int', 'Maybe [Double]', 'Maybe (Maybe (Maybe Char))', etc. Del mismo modo, no hay valores de tipo ' (->) Zero', pero hay valores de tipo '(->) Zero Zero', es decir,' Zero -> Zero'. – Ben

+0

Gracias Ben. Me faltaba la notación infijo vs prefijo, ¡pero está claro ahora! – crockeea

Cuestiones relacionadas