Sto cercando di imparare GHC Generics. Dopo aver esaminato diversi esempi, ho voluto provare a creare istanze generiche Functor
(ignorando che GHC può ricavarle automaticamente per me). Tuttavia, mi sono reso conto che non ho idea di come lavorare con tipi di dati parametrizzati con Generics, tutti gli esempi che ho visto erano di tipo *
. È possibile, e se sì, come? (Sono interessato anche ad altri framework simili, come SYB.)Come costruire istanze di Functor generiche utilizzando GHC.Generics (o altri framework simili)?
9
A
risposta
8
Il posto migliore per cercare molte funzioni di esempio utilizzando GHC Generics è lo generic-deriving
package. C'è una definizione generica della classe Functor
. La copia (leggermente semplificata) da Generics.Deriving.Functor
:
class GFunctor' f where
gmap' :: (a -> b) -> f a -> f b
instance GFunctor' U1 where
gmap' _ U1 = U1
instance GFunctor' Par1 where
gmap' f (Par1 a) = Par1 (f a)
instance GFunctor' (K1 i c) where
gmap' _ (K1 a) = K1 a
instance (GFunctor f) => GFunctor' (Rec1 f) where
gmap' f (Rec1 a) = Rec1 (gmap f a)
instance (GFunctor' f) => GFunctor' (M1 i c f) where
gmap' f (M1 a) = M1 (gmap' f a)
instance (GFunctor' f, GFunctor' g) => GFunctor' (f :+: g) where
gmap' f (L1 a) = L1 (gmap' f a)
gmap' f (R1 a) = R1 (gmap' f a)
instance (GFunctor' f, GFunctor' g) => GFunctor' (f :*: g) where
gmap' f (a :*: b) = gmap' f a :*: gmap' f b
instance (GFunctor f, GFunctor' g) => GFunctor' (f :.: g) where
gmap' f (Comp1 x) = Comp1 (gmap (gmap' f) x)
class GFunctor f where
gmap :: (a -> b) -> f a -> f b
default gmap :: (Generic1 f, GFunctor' (Rep1 f))
=> (a -> b) -> f a -> f b
gmap = gmapdefault
gmapdefault :: (Generic1 f, GFunctor' (Rep1 f))
=> (a -> b) -> f a -> f b
gmapdefault f = to1 . gmap' f . from1
Per utilizzare questo su un tipo di dati, è necessario ricavare Generic1
piuttosto che Generic
. La differenza chiave della rappresentazione Generic1
consiste nel fatto che utilizza il tipo di dati Par1
che codifica le posizioni dei parametri.
3
Esiste una classe Generic1
per tipi di dati di tipo * -> *
. Lavorare con esso è per lo più lo stesso con tipi di dati di tipo *
, ad eccezione del parametro Par1
. L'ho usato nel mio unfoldable package per esempio.
Problemi correlati
- 1. Derivazione di istanze predefinite utilizzando GHC.Generics
- 2. Fotocamere multiple in libgdx (probabilmente simili in altri framework)
- 3. Functor/istanze applicative per stato in Haskell
- 4. Costruire istanze monade efficienti su `Set` (e altri contenitori con vincoli) usando il monad di continuazione
- 5. Come costruire in modo condizionale altri progetti?
- 6. Esistono altri linguaggi simili a XML?
- 7. Django: esempio di relazioni generiche usando il framework contenttypes?
- 8. GLKMatrix4 (e altri simili) mancanti in swift?
- 9. Rimuovere le istanze da un elenco utilizzando LINQ o Lambda?
- 10. Come costruire un framework plug-in C#?
- 11. UIActivityIndicatorView o simili
- 12. C'è qualche framework o progetto Web che fornisce funzionalità simili a "Muro"
- 13. È possibile creare giochi Android in Go utilizzando NDK con cgo e/o SWIG o simili?
- 14. Utilizzare chiamato istanze per altri casi
- 15. Costruire il proprio framework php
- 16. Xcode: Framework collegati vs altri framework
- 17. FMAP Strict utilizzando solo Functor, non Monade
- 18. std :: sort utilizzando il functor ereditato
- 19. Interfacce generiche e non generiche
- 20. interfacce generiche
- 21. Elimina tag html in sed o simili
- 22. Come faccio a distinguere tra firme generiche e non generiche utilizzando GetMethod in .NET?
- 23. come costruire query di inserimento multiple in Zend Framework
- 24. Classe locale C++ come functor
- 25. Rundown di Ember-CLI che lo utilizza con Laravel o altri framework di backend
- 26. Come costruire un Modulo in play framework 2
- 27. Come fare un lavoro di Jenkins/Hudson per sorvegliare altri lavori e decidere se costruire o meno?
- 28. Come registrare interfacce generiche in StructureMap
- 29. Come costruire un $ o query in MgO
- 30. Elenco di interfacce generiche
GHC ricava automaticamente istanze di 'Generic1'? –
@ PetrPudlák Non completamente automatico. Ma con l'estensione di linguaggio 'DeriveGeneric', puoi usare' derivando Generic' e 'derivando Generic1' (dove quest'ultimo funziona solo per i tipi di dati con almeno un parametro, l'ultimo parametro è di tipo' * '). – kosmikus
@kosmikus Grazie. Sfortunatamente per il mio obiettivo mi piacerebbe lavorare con tipi più complessi, quindi probabilmente dovrò usare Template Haskell. –