2013-07-02 11 views
7

sto fondamentalmente tentando di vedere se riesco a emulare un quadro ORM all'interno di Haskell, in modo che se un utente vuole fare un modello di database, che avrebbero fatto una cosa del genereUtilizzando derivanti generico con un record Haskell

data Car = Car { 
     company :: String, 
     model :: String, 
     year :: Int 
     } deriving (Model) 

Dove il tavolo sarebbe "Car", e le colonne sarebbero la società, modello, anno

Per fare questo all'interno di Haskell, devi usare una combinazione di classi e generici, ed è qui che mi sto bloccando . Utilizzando questo tutorial (http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/generic-programming.html), sono arrivato fino a questo (che è stato appena fondamentalmente la copia e la ridenominazione in modo da poter ottenere il codice di lavoro)

{-# LANGUAGE DeriveGeneric, TypeOperators, TypeSynonymInstances, FlexibleInstances #-} 

module Main where 
import GHC.Generics 

class SModel b where 
     s_new :: b -> IO() 

instance SModel Int where 
     s_new s = putStrLn s++":Int" 

instance SModel Integer where 
     s_new s = putStrLn s++":Integer" 

instance SModel String where 
     s_new s = putStrLn s++":String"  

class Model m where 
     new :: m a -> IO() 

instance Model U1 where 
     new U1 = putStrLn "unit" 

instance (Model a, Model b) => Model (a :*: b) where 
     new (a :*: b) = do 
       new a 
       new b 

instance (Model a, Model b) => Model (a :+: b) where 
     new (L1 x) = new x 
     new (R1 x) = new x 

instance (Model a) => Model (M1 i c a) where 
     new (M1 x) = new x 

instance (SModel a) => Model (K1 i a) where 
     new (K1 x) = s_new x 

data Car = Car { 
     company :: String, 
     model :: String, 
     year :: Int 
     } deriving (Model) 

Il codice precedente produce l'errore

Cannot derive well-kinded instance of form `Model (Car ...)' 
     Class `Model' expects an argument of kind `* -> *' 
    In the data declaration for `Car' 

E Sono abbastanza bloccato a questo punto, credo di aver già istanziato tutti i tipi generici richiesti per coprire un record

+6

Non è possibile utilizzare 'Modello' in una clausola di derivazione. Invece, dovresti derivare 'Generic' e quindi fornire un'istanza predefinita per' SModel'. Vedere la Guida dell'utente GHC su "Default generici". C'è anche qualche documentazione preliminare migliorata su https://github.com/kosmikus/generic-deriving/blob/master/src/Generics/Deriving/Base.hs – kosmikus

+0

Quindi Haskell non ha alcun supporto ufficiale per l'utilizzo del derivare per qualcosa a parte lo spettacolo, eq (e alcuni degli altri derivati ​​incorporabili) – mdedetrich

risposta

7

Come ha detto kosmikus nel suo commento, non è possibile derivare direttamente Model. In primo luogo è necessaria una classe 'front-end' per Model fornire un generico predefinito, che potrebbe assomigliare a questo:

class FModel a where 
    fnew :: a -> IO() 

    default new :: (Generic a, Model (Rep a)) => a -> IO() 
    fnew = new . from 

allora si può solo fare:

Car = ... deriving Generic 
instance FModel Car 

E si ha l'istanza desiderata.

+1

Se anche questo è troppo "boilerplate" (ottiene di più se hai più classi che vuoi "derivare"), puoi usare TemplateHaskell per generare tutte le istanze vuote, anche se non lo farei fallo se hai solo una lezione. – bennofs

Problemi correlati