2016-02-26 3 views
3

Имея такую ​​запись:Получить текстовое представление поля записи?

data Sleep = Sleep 
    { _duration :: Maybe Int 
    , _drunk :: Bool 
    } 

Есть ли способ сделать следующее:

deriveSomething ''Sleep 

fieldName duration :: String -- "duration" 

мне это нужно для типизированного DB обновлений конкретных мест, а именно:

setField connection key duration (Just 50) 

It должен быть DB-агностиком, хотя (таким образом, opaleye и т. д. отсутствует).

(Если это может быть достигнуто с помощью стандартного пакета, как lens еще лучше, но я не смог найти что-нибудь.)

+0

Я думаю, что 'aeson' делает что-то подобное при сериализации в JSON, может быть, вы найдете что-то полезное там – epsilonhalbe

+0

@epsilonhalbe: посмотрите мой комментарий ниже. –

ответ

2

Вы можете сделать это с помощью Data.Data:

{-# LANGUAGE DeriveDataTypeable #-} 
import Data.Data 

data Sleep = Sleep 
    { _duration :: Maybe Int 
    , _drunk :: Bool 
    } deriving (Typeable, Data) 

fieldNames :: Data a => a -> [String] 
fieldNames = constrFields . toConstr 

Пример:

> fieldNames (Sleep undefined undefined) 
["_duration", "_drunk"] 

Вам нужно будет решить, как вы хотите преобразовать имена в столбцы базы данных после этого, но это должно быть довольно легко.

Для этого требуется значение, созданное с использованием конкретного конструктора, помните, что типы данных могут иметь много конструкторов. Существует на самом деле не способ обойти это, но вы могли бы иметь что-то вроде

sleepFieldNames :: [String] 
sleepFieldNames = fieldNames (Sleep undefined undefined) 

Так что вам не придется держать его перерасчета.

+0

примечание стороны: вам понадобится '{- # LANGUAGE DeriveDataTypeable # -}', чтобы сделать эту работу – epsilonhalbe

+0

К сожалению, мне нужно текстовое представление для каждого * конкретного * поля, а не для всех полей одновременно, т.е. мне буквально нужно что-то вроде ' fieldName :: Field -> String', где 'Field' каким-то образом определяется из определения типа данных. –

+0

@PhilipKamenarsky Я не знаю, возможно ли это, если вы не напишете какой-нибудь шаблонный шаблон. GHC действительно видит ваши аксессоры как функции, на самом деле вы получаете синтаксический сахар для 'data Sleep = Sleep (Maybe Int) Bool; _duration :: Sleep -> Maybe Int; _drunk :: Sleep -> Bool', при этом реализации будут доступны только вам. Есть еще какая-то дополнительная магия, но без некоторого TH для генерации 'duration' для вас, как для некоторого типа« Field »(может быть, какой-то помеченный объектив?), Вы не сможете. – bheklilr

Смежные вопросы