Haskell получает типы Конструктора Данных

Мне было интересно, если дан конструктор, такой как:

data UserType = User
  { username :: String
  , password :: String
  } -- deriving whatever necessary

Какой самый простой способ для меня, чтобы получить что-то на линии [("username", String), ("password", String)]Если не считать просто ручную запись. Теперь для этого конкретного примера хорошо просто написать его, но для сложной модели базы данных с большим количеством различных полей это было бы довольно раздражающим.

До сих пор я просмотрел Typeable а также Data но пока самое близкое, что я нашел, это:

user = User "admin" "pass"
constrFields (toConstr user)

Но это не говорит мне типы, это просто возвращает ["username", "password"] и это также требует, чтобы я создал экземпляр пользователя.

1 ответ

Решение

Я просто выбил функцию с помощью Data.Typeable что позволяет превратить конструктор в список TypeRepс его аргументами. В сочетании с constrFields Вы обнаружили, что можете объединить их, чтобы получить желаемый результат:

{-# LANGUAGE DeriveDataTypeable #-}

module Foo where
import Data.Typeable
import Data.Typeable.Internal(funTc)

getConsArguments c = go (typeOf c)
   where go x = let (con, rest) = splitTyConApp x    
                in if con == funTc         
                   then case rest of (c:cs:[]) -> c : go cs
                                     _ -> error "arrows always take two arguments"
                   else []                      

дано data Foo = Foo {a :: String, b :: Int} deriving Typeable, мы получаем

*> getConsArguments Foo
[[Char],Int]

Как можно было бы надеяться.


О том, как получить имена полей без использования самого значения заполненного типа данных, вот решение:

constrFields . head . dataTypeConstrs $ dataTypeOf (undefined :: Foo)
Другие вопросы по тегам