2013-08-18 2 views
11

Допустим, мы имеемHaskell: Получить имя конструктора данных в виде строки

data D = X Int | Y Int Int | Z String 

Я хотел бы иметь функцию getDConst

getDConst :: D -> String 

что возвращает либо "X", "Y", или " Z ", в соответствии с конструктором данных, используемым для его ввода. Есть ли общий способ написать это без необходимости делать case на каждом конструкторе данных? (Я в порядке с решениями, опираясь на Data.Typeable или что-то подобное)

ответ

13

нашел решение сам, но оставив этот вопрос, чтобы помочь другим:

import Data.Data 
data D = X Int | Y Int Int deriving (Data,Typeable) 

let result = show $ toConstr (X 3) -- result contains what we wanted 
+1

Если кто-то и получает ошибку с этим: Попробуйте добавить '{- # LANGUAGE DeriveDataTypeable # -}' в начало файла. Это необходимо в GHC, когда вы получаете данные и тип. – jPlatte

6

Если вы не хотите использовать Typeable, вы можете также сделайте это с Show.

getDConst :: D -> String 
getDConst = head . words . show 

Show не будет выводить все поля, потому что лень. Вы можете проверить это подножка этот код в ghci:

Prelude> data D = D [Int] deriving (Show) 
Prelude> getDConst $ D [1..] 
"D" 
+0

Возможно, вы также захотите реализовать пользовательский вывод show, который не включает конструктор. – kqr

+0

'show' ленив, так что это, вероятно, будет не очень медленным. Обратите внимание, как 'take 5 (show (Just undefined))' отлично работает. –

+2

Вы имеете в виду слова, а не 'unwords'. (На самом деле, я бы написал что-то вроде 'takeWhile (/ = ''). Show') – Lynn