2016-06-13 90 views
8

Quello che voglio è quello di scrivere qualcosa del genere:Control.Arrow: Perché "let (a, b) = (first, second)" non riesce?

let (a,b) = if *condition* then (first, second) else (second, first)

ho scoperto che non posso scrivere anche questo:

let (a,b) = (first,second)

Non riesce con un errore:

<interactive>:7:5:                               
Could not deduce (Arrow a0)                            
from the context (Arrow a) 
    bound by the inferred type for `a': 
      Arrow a => a b c -> a (b, d) (c, d) 
    at <interactive>:7:5-26 
The type variable `a0' is ambiguous 
When checking that `a' has the inferred type 
    a :: forall (a :: * -> * -> *) b c d. 
     Arrow a => 
     a b c -> a (b, d) (c, d) 
Probable cause: the inferred type is ambiguous 

<interactive>:7:5: 
Could not deduce (Arrow a0) 
from the context (Arrow a) 
    bound by the inferred type for `b': 
      Arrow a => a b c -> a (d, b) (d, c) 
    at <interactive>:7:5-26 
The type variable `a0' is ambiguous 
When checking that `b' has the inferred type 
    b :: forall (a :: * -> * -> *) b c d. 
     Arrow a => 
     a b c -> a (d, b) (d, c) 
Probable cause: the inferred type is ambiguous 
+5

Simon Peyton-Jones ha una grande e-mail ad una delle mailing list (che ora sto avendo problemi a trovare), che discute le sottigliezze di attacchi modello typechecking come Questo. È così sottile, infatti, che il rapporto Haskell98 ha trascurato completamente la questione, e il comitato ha dedicato un po 'di tempo a riflettere su come dovrebbe essere fatto il typechecking per i binding di pattern prima di scrivere il report di Haskell 2010. Vorrei scrivere una risposta, tranne che non mi fido di me stesso per ottenere le sottigliezze giuste senza l'e-mail di SPJ di fronte a me ... –

+0

Ad una ipotesi, il problema qui è che il lato destro del bind ottiene il tipo inferito 'forall a1 a2. (Freccia a1, Freccia a2) => (a1 ..., a2 ...) 'in contrapposizione a' (forall a1. Arrow a1 => ..., forall a2. Arrow a2 => ...) ', così il forall viene spostato * fuori * dalla tupla, e uno dei valori nella coppia non è completamente polimorfico. –

risposta

2

Molto poco, si tenta di costruire il tipo impredicativa che GHC non posso dedurre. Si può fare:

λ Control.Arrow > let (a,b) = (first, second) :: Arrow a => (a b b -> a (b, b) (b, b), a b b -> a (b, b) (b, b)) 
λ Control.Arrow > :t a 
a :: Arrow a => a b b -> a (b, b) (b, b) 
λ Control.Arrow > :t b 
b :: Arrow a => a b b -> a (b, b) (b, b) 

o

:set -XImpredicativeTypes 
λ Control.Arrow > let (a,b) = (first, second) :: (Arrow a => a b b -> a (b, b) (b, b), Arrow a => a b b -> a (b, b) (b, b)) 
λ Control.Arrow > :t a 
a :: Arrow a => a b b -> a (b, b) (b, b) 
λ Control.Arrow > :t b 
b :: Arrow a => a b b -> a (b, b) (b, b) 

, ma non si può fare:

λ Control.Arrow > let (a,b) = (first, second) :: (Arrow a, Arrow a') => (a b b -> a (b, b) (b, b), a' b b -> a' (b, b) (b, b)) 

Per isolare il problema, questo funziona:

λ Control.Arrow > let p = (first, second) :: (Arrow a, Arrow a') => (a b b -> a (b, b) (b, b), a' b b -> a' (b, b) (b, b)); 
λ Control.Arrow > :t p 
p :: (Arrow a', Arrow a) => 
    (a b b -> a (b, b) (b, b), a' b b -> a' (b, b) (b, b)) 

ma quando si tenta di associare a quel modello:

λ Control.Arrow > let (a, b) = p 

fallisce. Vincoli sono al di fuori del tipo coppia, e sono ridondanti per altra metà della coppia, come

λ Control.Arrow > :set -XImpredicativeTypes 
λ Control.Arrow > let p = (first, second) :: (Arrow a => a b b -> a (b, b) (b, b), Arrow a => a b b -> a (b, b) (b, b)) 
λ Control.Arrow > let (a, b) = p 

opere.


esempio semplice:

λ Prelude Data.Monoid > :t (mappend,()) 
(mappend,()) :: Monoid a => (a -> a -> a,()) 
λ Prelude Data.Monoid > let (a, b) = (mappend,()) 

<interactive>:12:5: 
    No instance for (Monoid a0) 
     arising from the ambiguity check for ‘b’ 
    The type variable ‘a0’ is ambiguous 
    When checking that ‘b’ has the inferred type ‘()’ 
    Probable cause: the inferred type is ambiguous 

One devono trasportare vincoli sopra, ma non c'è a nel tipo di (), cioè Monoid a =>() è digitare ambigua.


Nota: let (a,b) = ((+), (*)) sembra funzionare.Non ho idea di come e perché Num viene trattato in maniera particolare:

λ Prelude Data.Monoid > let x =() :: Num a =>() 
λ Prelude Data.Monoid > :t x 
x ::() 
λ Prelude Data.Monoid > let x =() :: Monoid m =>() 

<interactive>:12:9: 
    No instance for (Monoid m0) 
    ... 
1

Sembra che tu stia correndo monomorphism restriction. Questa è solo una limitazione dell'inferenza di tipo di Haskell e puoi aggirarla aggiungendo una firma di tipo esplicita.

import Control.Arrow 

foo :: (Arrow a, Arrow a1) => (a b c -> a (b, d) (c, d), a1 b1 c1 -> a1 (d1, b1) (d1, c1)) 
foo = (first, second) 

Questo codice typechecks bene con la firma tipo per foo ma dà quel errore di compilazione "variabile ambiguo" se si rimuove.

BTW, la firma del tipo che ho usato era quella dedotta da :t (first, second) in GHCI. Dal momento che si vuole (first, second) e (second, first) di avere lo stesso tipo, probabilmente si desidera utilizzare un tipo più specifico l'annotazione, come ad esempio la seguente:

foo :: (Arrow a) => (a b b -> a (b, b) (b, b), a b b -> a (b, b) (b, b)) 
+1

Ha '(a, b) = ...', non 'foo = ...', che fa la differenza. Questa non è la restrizione del monomorfismo. Spegnilo e vedi di persona. Posso garantire che non l'hai fatto, perché il codice che hai pubblicato non ha nemmeno la giusta importazione. –

+0

@DanielWagner: Mi dispiace per l'importazione. Quello era solo un errore di battitura e il codice che stavo effettivamente correndo aveva il corretto "Control.Arrow" nella parte superiore del tutto :) – hugomg

+3

Tuttavia la tua risposta non è corretta, a causa dell'altra obiezione che ho sollevato: '(a, b) = ... 'e' foo = ... 'non si comportano allo stesso modo. –