2016-01-23 5 views
1

Я использую модуль Data.Data для динамического захвата некоторых данных типа данных во время выполнения. Давайте предположим, что есть тип данных, как data Place = Place {name :: Text, description :: Text} deriving (Data):Динамически извлекать значения типа данных

  • я мог восстановить его конструктор с toConstrtoConstr (Place "Some place" "Bla") который даст мне Place
  • Я мог бы получить его метку поля с constrFieldsconstrFields $ toConstr (Place "Some place" "Bla"), который даст мне ["name", "description"]

Теперь мне нужно получить значения, с помощью которых я построил Place, поэтому для Place "Some place" "Bla" Я хочу извлечь что-то вроде ["Some place", "Bla"], поймать то, что в моей треске e Я не знаю, что это значение данных является Place, это может быть любой тип данных, который выводит класс Data. Код Icn:

getValuesOfDataValue :: (Data a) => a -> [String] 
getValuesOfDataValue a = 
    -- some magic generic function 

data Place = Place {name :: Text, description :: Text} deriving (Data) 
-- the code below should evaluate to ["Some place", "Bla"] 
getValuesOfDataValue (Place "Some place" "Bla") 

data SomeType = SomeType {num :: Integer, num2 :: Integer} deriving (Data) 
-- the code below should evaluate to [300, 500] 
getValuesOfDataValue (SomeType 300 500) 

Как это сделать?

Примечание: getValuesOfDataValue не должен возвращать ровно тип [String], он просто должен иметь значения, упакованные в что-то.

+0

Просьба предоставить более/лучший код. Топ-уровень 'let' не является законным Haskell, и неясно, что должен делать 'constrFields'. Это также помогло бы нам обоим, если бы вы дали типы для 'p',' c' и т. Д. – crockeea

+1

Взгляните на 'gfoldl'. – PyRulez

+0

Пожалуйста, добавьте действительный код Haskell, который описывает проблему, с которой вы сталкиваетесь. –

ответ

3

Использовать cast из семейства Typeable (напомним, что Data является подклассом Typeable).

λ> import Data.Text 
λ> import Data.Data 
λ> :set -XDeriveDataTypeable -XOverloadedStrings 
λ> data Triple = Triple Text Text Int deriving (Show, Data) 
λ> gmapQ cast (Triple "a" "b" 1821) :: [Maybe Text] 
[Just "a",Just "b",Nothing] 
λ> gmapQ cast (Triple "a" "b" 1821) :: [Maybe Int] 
[Nothing,Nothing,Just 1821] 

Получай, динамически типизированных языков программирования.

Если вы не знаете, какой тип вы хотите заранее, вы можете также stringify значения с gshow из syb пакета:

λ> :set -package syb 
λ> import Data.Generics.Text 
λ> data Triple = Triple Text Text Int deriving (Data) 
λ> gmapQ gshow (Triple "a" "b" 1821) 
["(pack \"a\")","(pack \"b\")","(1821)"] 

Я предупреждаю вас, хотя: не зная, какой тип вы хотите заранее сурово ограничивает то, что вы можете делать с дженериками. Не все может быть натянуто, и даже когда они уродливы (как видно выше). Даже зная, белый список, какие типы вы хотите, поможет вам существенно:

λ> import Control.Arrow 
λ> :set -XScopedTypeVariables 
λ> let show' (proxy :: Proxy a) = Kleisli (\x -> show <$> (cast x :: Maybe a)) 
λ> gmapQ (runKleisli (show' (Proxy :: Proxy Int) <+> show' (Proxy :: Proxy Text))) (Triple "a" "b" 1821) 
["a","b","1821"] 

Примечание: getValuesOfDataValue не должен возвращать именно тип [String], это просто необходимо иметь значения, упакованные в чем-то.

Вопрос заключается в том, что упаковать его в пути gshow работы является то, что она рекурсивно вызывает gmapQ (и его помощника extQ, который построен из gmapQ и cast) на Data a => a значение:.

-- | Generic show: an alternative to \"deriving Show\" 
gshow :: Data a => a -> String 
gshow x = gshows x "" 

-- | Generic shows 
gshows :: Data a => a -> ShowS 

-- This is a prefix-show using surrounding "(" and ")", 
-- where we recurse into subterms with gmapQ. 
gshows = (\t -> 
       showChar '(' 
       . (showString . showConstr . toConstr $ t) 
       . (foldr (.) id . gmapQ ((showChar ' ' .) . gshows) $ t) 
       . showChar ')' 
     ) `extQ` (shows :: String -> ShowS) 

У этого есть базовый случай String -> ShowS, поэтому всякий раз, когда он попадает в строку, он знает, что возвращает его и завершает. Не зная подробностей о вашем проблемном домене, я бы сказал вам выйти и создать свой собственный gshows, используя ту же стратегию. В самом общем случае, когда вы хотите упаковать каждый тип, ответа не может быть, но, возможно, что-то конкретное существует для вашей конкретной задачи.

+0

Он работает, но необходимость указывать типы (:: [Может быть, что-либо]) приведет к еще одному уровню сложности, так как мне придется динамически их находить (помните, что в коде нет понятия, который имеет дело с «тройным» или что-нибудь еще). Во всяком случае thx;) – BrunoRB

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