Использование общего вывода с записью Haskell

Я в основном пытаюсь увидеть, могу ли я эмулировать структуру ORM в Haskell, так что, если пользователь хочет сделать модель базы данных, они сделают что-то вроде этого

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

где таблица будет "автомобиль", а столбцы будут компанией,моделью, годом

чтобы сделать это в Haskell, вы должны использовать комбинацию классов и дженериков, и вот где я застрял. Используя этот учебник (http://www.haskell.org/ghc/docs/7.4.1/html/users_guide/generic-programming.html), я придумал это (который просто в основном копировал и переименовывал, чтобы я мог заставить код работать)

{-# 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)

приведенный выше код выдает ошибку

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

и я вроде как застрял на этом этапе, я считаю, что я уже создал все необходимые общие типы, чтобы покрыть запись

1 ответов


As kosmikus сказал в своем комментарии, вы не можете вывести Model напрямую. Сначала вам нужен класс "front-end" для Model предоставление общего значения по умолчанию, которое может выглядеть следующим образом:

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

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

затем вы можете просто сделать:

Car = ... deriving Generic
instance FModel Car

и у вас есть нужный экземпляр.