2012-02-27 10 views
7

Quiero crear una tupla que contenga una flecha y una cadena que describa la flecha. Si lo hago con funciones (en vez de flechas), las obras siguientes, como se esperaba:Haskell Flechas dentro de Tuples

funTimes10 = (*10) 
describe10 = "times 10" 

tuple10 :: (Num b) => ((b -> b), String) 
tuple10 = (,) funTimes10 describe10 

puedo tener acceso a la función con fst, y con snd Me da la cadena de descripción de la función.

Sin embargo, si Puedo cambiar la función con una flecha, como en el siguiente:

aTuple10 :: (Arrow a, Num b) => (a b b, String) 
aTuple10 = (,) (arr funTimes10) describe10 
  • fst todavía funciona y devuelve mi flecha, pero
  • i no recibe ninguna cadena de descripción con snd.

Sólo tengo este error mensaje:

Ambiguous type variable `a0' in the constraint: 
    (Arrow a0) arising from a use of `aTuple10' 
Probable fix: add a type signature that fixes these type variable(s) 
In the first argument of `snd', namely `aTuple10' 
In the expression: (snd aTuple10) 
In an equation for `it': it = (snd aTuple10) 

¿Por qué aparece este error, y lo que debo hacer, para evitarlo? mirada

Respuesta

9

Vamos en el tipo de snd:

snd :: (foo, x) -> x 

(I renombró las variables de tipo para mayor claridad)

Lo que los estados tipo es que para una tupla con tipos foo y x, devolver algo de tipo x. Algo importante para saber aquí es que, si bien el sistema de valores también es conocido. el tiempo de ejecución en Haskell es flojo, el sistema de tipos de Haskell es estricto, lo que significa que se deben conocer los tipos de foo y x antes de llamar al snd.

En el primer caso, cuando sólo hay un Num b => (b -> b, String), llamando snd dejará b ambigua, ya que no menciona su tipo concreto en cualquier lugar, y no puede inferirse del tipo de retorno, ya que es distinto foo ~ b desde x. En otras palabras: como (b, b) puede ser una tupla de cualquier tipo de número, y el verificador de tipos no puede determinar cuál, es ambiguo. El truco aquí es que haremos que entren en vigencia las reglas de incumplimiento de Haskell, que establecen que si un tipo numérico es ambiguo, debería establecerse de manera predeterminada en Integer. Si hubiera activado las advertencias con -Wall, habría dicho que esto está sucediendo. Por lo tanto, nuestro tipo se convierte en (Integer -> Integer, String) y snd se puede llamar.

En el segundo caso, sin embargo, todavía logramos inferir b a través de las reglas predeterminadas, pero no hay predeterminado Arrow para a, ¡así que estamos atascados! ¡Debes especificar explícitamente qué flecha quieres para continuar! Usted puede hacer esto mediante el uso de un primer valor de aTuple10 en otro lugar:

let bla = aTuple10 -- We do this because `aTuple10` can have type variables, but `bla` cannot (by default) 
fst bla (23 :: Int) -- This fixes the type of `bla`, so that `a ~ (->)` and `b ~ Int` 
print $ snd bla  -- So the arrow isn't ambiguous here 

...o simplemente puede especificar el tipo que desea:

print $ snd (aTuple10 :: (Int -> Int, String)) 

PS si desea cambiar el tipo predeterminado de números ambiguos, el default keyword puede ayudarte.

+0

eso es exactamente;) thx – frosch03

+1

Cómo irritante. Uno esperaría que el sistema de tipos pueda concluir que 'snd aTuple10' tiene el tipo' String'; podría esto ser considerado un error en la implementación? Seguramente Haskell 2010 no especifica tal comportamiento. Uno podría argumentar que si la implementación no sabe qué tipo tiene la primera cosa, no sabrá dónde está la segunda cosa en la memoria, pero dado que estamos tratando aquí con tuplas en caja, siempre debe haber dos punteros, y por lo tanto el segundo elemento es fácilmente localizable, independientemente del tipo del primero. –

+2

Una función como 'clase Boolish a where toBool :: a -> Bool; foo :: Boolish a => (a, b) -> b; foo (a, b) = if toBool a then b else undefined' es concebible, por lo que el resultado de la función puede depender de un parámetro ambiguo. Special-casing para 'snd' sería extraño en esa situación. – dflemstr

-1

traté de compilar este:

import Control.Arrow 

funTimes10 = (*10) 
describe10 = "times 10" 

tuple10 :: (Num b) => ((b -> b), String) 
tuple10 = (,) funTimes10 describe10 

aTuple10 :: (Arrow a, Num b) => (a b b, String) 
aTuple10 = (,) (arr funTimes10) describe10 

Pero me sale esto:

Could not deduce (b ~ Integer) 
from the context (Arrow a, Num b) 
    bound by the type signature for 
      aTuple10 :: (Arrow a, Num b) => (a b b, String) 
    at D:\dev\haskell\arr_tuple.hs:10:1-42 
    `b' is a rigid type variable bound by 
     the type signature for 
     aTuple10 :: (Arrow a, Num b) => (a b b, String) 
     at D:\dev\haskell\arr_tuple.hs:10:1 
Expected type: b -> b 
    Actual type: Integer -> Integer 
In the first argument of `arr', namely `funTimes10' 
In the first argument of `(,)', namely `(arr funTimes10)' 

lo tanto, mi conjetura es que usted tiene que decidir qué flecha instancia que desea utilizar. Es decir. es posible que deba especificar el tipo concreto de arr funTimes con una anotación.

+0

El error aquí no tiene ninguna relación con el problema en cuestión. Aparece porque olvidó una firma de tipo para 'funTimes10'. Consulte la [Restricción de monomorfismo] (http://www.haskell.org/haskellwiki/Monomorphism_restriction). – dflemstr

+0

@dflemstr ¿Mi respuesta muestra un problema con la pregunta original? ** I ** no olvidé una firma de tipo, no estaba allí en la publicación original. Aunque no describí el problema subyacente (porque no lo vi), no creo que valga la pena votar mi respuesta. – Andre

+1

Creo que el OP simplemente copió la definición de sus funciones para demostrar qué tipos de valores está usando. Tiene un '' FunTimes10'' polimórfico, o habría obtenido un error diferente. – dflemstr

Cuestiones relacionadas