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)