5

Che diavolo sta succedendo qui:non poteva competere tipo `* 'contro' #'

"Couldn't match kind `*' against `#'" 

stavo provando quanto segue in GHCi utilizzando TemplateHaskell (ghci -XTemplateHaskell)

$(reify ''Show >>= dataToExpQ (const Nothing)) 

I speravo di ottenere un Exp fuori da questo (che ha un'istanza di Show). Lo sto facendo per inserire informazioni sui tipi haskell in un'applicazione in modo tale che siano disponibili come dati reali, non come stringa.

Il mio obiettivo è la seguente:

info :: Info 
info = $(reify ''Show >>= dataToExpQ (const Nothing)) 

Io davvero non capisco che messaggio di errore, ciò che è '#' comunque? Se c'è #, c'è anche # -> # o * -> #? È qualcosa che si riferisce a generi come i tipi relativi ai tipi (anche se non saprei cosa potrebbe essere)?


Va bene, così io capire ora che GHC ha una gerarchia di genere e che `#' è un tipo speciale di tipi senza custodia. Tutto bene, ma perché compare questo errore? Forse i tipi non condivisi non giocano bene con il genercis?

Non sono completamente sicuro che questo abbia ancora senso per me, dal momento che considererei i tipi non condivisi come una ottimizzazione eseguita dal compilatore. Ho anche pensato che se esiste un'istanza di Data, deve essere presente per tutti i tipi che potrebbero essere inclusi nella struttura dei dati.

In seguito a ulteriori indagini, credo che Names ponga il problema, c'è un modo per aggirarli in dataToExpQ? Come usare quell'argomento comunque?

+5

'#' è il tipo di tipi unboxed, vedere http://stackoverflow.com/a/3034295/700253 – Vitus

+0

grazie per il suggerimento. quindi: come risolvere il problema :-)? – scravy

risposta

4

Hai ragione, sono i nomi a causare il problema. Più in particolare, il problema è che il tipo di dati NameFlavour ha numeri interi non archiviati in alcuni dei suoi campi.

C'è una nota di Eglefino nell'istanza Data NameFlavor che genera alcune bandiere rosse. E se si fa clic sul codice sorgente, si vedrà che la definizione gfoldl tratta essenzialmente gli interi non archiviati come interi. (In realtà non c'è molta altra scelta ...) Questo causa l'errore che stai vedendo perché dataToExpQ - ingannato dall'ingannevole Data NameFlavour - costruisce un termine Exp che applica NameU a un (Int :: *) quando NameU si aspetta effettivamente un (unboxed) (Int # :: #).

Quindi il problema è che l'istanza Data per NameFlavour disobeys l'invariante assunto da dataToExpQ. Ma non preoccuparti! Questo scenario rientra esattamente nella ragione per cui dataToExpQ accetta un argomento: l'argomento ci consente di fornire un trattamento speciale per tipi problematici. Di seguito, lo faccio per reificare correttamente i costruttori NameFlavour che hanno campi interi non archiviati.

Potrebbero esserci soluzioni per questo, ma non ne sono a conoscenza, quindi ho presentato quanto segue. Richiede un modulo separato a causa della restrizione di staging TH.

{-# LANGUAGE TemplateHaskell #-} 
{-# LANGUAGE MagicHash #-} 

module Stage0 where 

import Language.Haskell.TH 
import Language.Haskell.TH.Syntax 

import GHC.Types (Int(I#)) 
import GHC.Prim (Int#) 

unboxed :: Int# -> Q Exp 
unboxed i = litE $ intPrimL $ toInteger $ I# i -- TH does support unboxed literals 

nameFlavorToQExp :: NameFlavour -> Maybe (Q Exp) 
nameFlavorToQExp n = case n of 
    NameU i -> Just [| NameU $(unboxed i) |] 
    NameL i -> Just [| NameL $(unboxed i) |] 
    _ -> Nothing 

E quindi il seguente compila per me.

{-# LANGUAGE TemplateHaskell #-} 

import Language.Haskell.TH 
import Language.Haskell.TH.Quote 

import Generics.SYB 
import Stage0 

info :: Info 
info = $(reify ''Show >>= dataToExpQ (mkQ Nothing nameFlavorToQExp)) 

CAVEAT PROGRAMMATORE Gli interi unboxed stiamo facendo in quattro per qui corrispondono a "utenti unici" che GHC utilizza internamente. Non sono necessariamente previsti per la serializzazione. A seconda di come stai usando il valore informativo risultante, questo potrebbe causare esplosioni.

Nota anche durante la reimpostazione di Show, stai anche reificando ogni istanza di Show che è in ambito.

  • Ce ne sono molti, questo genera un termine sintattico piuttosto grande.

  • Come dice the documentation, queste istanze non includono le definizioni del metodo.

HTH.