Domanda

Ho questo codice:

type family Id obj :: *
type instance Id Box = Int
.

E voglio farlo in modo da poter sempre ottenere un'inT dalla famiglia Tipo ID.Riconosco che sarà richiesta una conversione.

Ho pensato che forse creare una classe funzionerebbe:

class IdToInt a where
  idToInt :: Id a -> Int

instance IdToInt Box where
  idToInt s = s
.

e questo in realtà compila.Ma quando provo a usarlo:

testFunc :: Id a -> Int
testFunc x = idToInt x
.

I Ottieni errori:

src/Snowfall/Spatial.hs:29:22:
Couldn't match type `Id a0' with `Id a'
NB: `Id' is a type function, and may not be injective
In the first argument of `idToInt', namely `x'
In the expression: idToInt x
In an equation for `testFunc': testFunc x = idToInt x
.

Allora, come posso creare una conversione per un ID familiare di tipo per ottenere un INT?

Basato sulla risposta di Ehird, ho provato quanto segue ma non funziona neanche:

class IdStuff a where
  type Id a :: *
  idToInt :: Id a -> Int

instance IdStuff Box where
  type Id Box = Int
  idToInt s = s

testFunc :: (IdStuff a) => Id a -> Int
testFunc x = idToInt x
.

Dà errore:

src/Snowfall/Spatial.hs:45:22:
Could not deduce (Id a0 ~ Id a)
from the context (IdStuff a)
  bound by the type signature for
             testFunc :: IdStuff a => Id a -> Int
  at src/Snowfall/Spatial.hs:45:1-22
NB: `Id' is a type function, and may not be injective
In the first argument of `idToInt', namely `x'
In the expression: idToInt x
In an equation for `testFunc': testFunc x = idToInt x
.

È stato utile?

Soluzione

Come altri hanno sottolineato, il problema è che il compilatore non può capire quale a da utilizzare.Le famiglie di dati sono una soluzione, ma un'alternativa a volte è più facile da lavorare è usare un testimone di tipo.

Cambia la tua classe su

class IdToInt a where
  idToInt :: a -> Id a -> Int

instance IdToInt Box where
  idToInt _ s = s

-- if you use this a lot, it's sometimes useful to create type witnesses to use
box = undefined :: Box

-- you can use it like
idToInt box someId

-- or
idToInt someBox (getId someBox)
.

La domanda di cui è necessario rispondere è, per qualsiasi dato Id, c'è solo un tipo a con cui dovrebbe apparire?Cioè, c'è una corrispondenza da una a una corrispondenza tra as e Id as?In tal caso, le famiglie di dati sono l'approccio corretto.Se no, potresti preferire un testimone.

Altri suggerimenti

non puoi.Avrai bisogno di testFunc :: (IdToInt a) => Id a -> Int.Tipo Le famiglie sono aperte, quindi chiunque può dichiarare

type instance Id Blah = ()
.

in qualsiasi momento e non offri alcuna funzione di conversione.La cosa migliore da fare è mettere la famiglia del tipo nella classe:

class HasId a where
  type Id a
  idToInt :: Id a -> Int

instance IdToInt Box where
  type Id Box = Int
  idToInt s = s
.

Avrai ancora bisogno del contesto, però.

Non è possibile utilizzare una funzione di tipo IdToInt a => Id a -> Int perché non c'è modo di determinare quale tipo a è.L'esempio seguente lo dimostra.

type family Id a :: *
type instance Id () = Int
type instance Id Char = Int

class IdToInt a where idToInt :: Id a -> Int

instance IdToInt () where idToInt x = x + 1
instance IdToInt Char where idToInt x = x - 1

main = print $ idToInt 1
.

Poiché Id () = Id Char = Int, il tipo di generatori di generazioneGode nel contesto di cui sopra è idToInt, che è uguale a Int -> Int e Id () -> Int.Ricorda che i metodi sovraccaricati vengono scelti in base al tipo.Entrambe le istanze di classe definiscono le funzioni Id Char -> Int che hanno tipo idToInt, quindi il controllo del tipo non può decidere quale utilizzare.

Dovresti utilizzare una famiglia dati invece di una famiglia di tipo e dichiarare le istanze di Newtype.

data family Id a :: *
newtype instance Id () = IdUnit Int
newtype instance Id Char = IdChar Int
.

Con un'istanza di newtype, Int -> Int e Id () è entrambi gli interni, ma hanno tipi diversi.Il tipo di un Id Char informa il controllo del tipo che funziona la funzione di sovraccarico da utilizzare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top