2013-04-10 81 views
3

假設我們有如何在數據隱藏的人的姓名和年齡= {人名::一,年齡::詮釋}派生顯示在Haskell

data People a = Person { name::a , age::Int} deriving Show 
在擁抱

當我輸入

> Person "Alihuseyn" 20 

我得到Person {name = "Alihuseyn", age = 20} 但我想得到Person Person "Alihuseyn" 20

我的意思是我怎樣才能在不改變數據的情況下隱藏名字和年齡的提及?

+8

那就不要導出'Show'實例,但自己編寫。如果您使用帶標記的字段來定義類型,則派生的'Show'實例將包含大括號和字段名稱。 – 2013-04-10 18:38:59

回答

11

您可以隨時爲您的所有類型提供自定義Show例如,如果你想:

data People a = Person { name::a , age::Int} 

instance (Show a) => Show (People a) where 
    show (Person name age) == "Person " ++ show name ++ " " ++ show age 

或可選擇地少優雅,編寫自定義訪問器:

data People a = Person a Int deriving Show 
name (Person n _) = n 
age (Person _ a) = a 

無論哪種方式,你必須更改People的聲明,否則你會被派生的Show實例卡住。

作爲一個側面說明,如果你有一個只有一個構造函數的數據類型,你通常命名型後的構造,所以這將是data Person a = Person { name :: a, age :: Int }

7

這使用GHC.Generics提供showsPrecDefault,它可以是很容易用來定義一個Show實例。

data Person a = Person { name :: a, age :: Int } deriving Generic 

instance Show a => Show (Person a) where showsPrec = showsPrecDefault 

>>> Person "Alihuseyn" 20 
Person "Alihuseyn" 20 

showsPrecDefault的定義如下。

{-# LANGUAGE 
    DeriveGeneric 
    , FlexibleContexts 
    , FlexibleInstances 
    , KindSignatures 
    , TypeOperators 
    , TypeSynonymInstances #-} 
import GHC.Generics 

class GShow f where 
    gshowsPrec :: Int -> f a -> ShowS 

instance GShow U1 where 
    gshowsPrec _ U1 = id 

instance Show c => GShow (Rec0 c) where 
    gshowsPrec p = showsPrec p . unK1 

instance GShow f => GShow (D1 d f) where 
    gshowsPrec p = gshowsPrec p . unM1 

instance Constructor c => GShow (C1 c U1) where 
    gshowsPrec _ [email protected](M1 U1) = showParen (isInfix c) (showString (conName c)) 

instance (Constructor c, GShow (M1 i c f)) => GShow (C1 c (M1 i c f)) where 
    gshowsPrec = gshowsPrec' 

instance (Constructor c, GShow (f :+: g)) => GShow (C1 c (f :+: g)) where 
    gshowsPrec = gshowsPrec' 

instance (Constructor c, GShow (f :*: g)) => GShow (C1 c (f :*: g)) where 
    gshowsPrec = gshowsPrec' 

gshowsPrec' :: (Constructor c, GShow f) => Int -> C1 c f p -> ShowS 
gshowsPrec' p [email protected](M1 f) = 
    showParen (p > 10) $ 
    showParen (isInfix c) (showString (conName c)) . 
    showChar ' ' . 
    gshowsPrec 11 f 

isInfix :: Constructor c => t c (f :: * -> *) a -> Bool 
isInfix c = case conFixity c of 
    Infix _ _ -> True 
    _ -> False 

instance GShow f => GShow (S1 s f) where 
    gshowsPrec p = gshowsPrec p . unM1 

instance (GShow a, GShow b) => GShow (a :+: b) where 
    gshowsPrec p (L1 a) = gshowsPrec p a 
    gshowsPrec p (R1 b) = gshowsPrec p b 

instance (GShow a, GShow b) => GShow (a :*: b) where 
    gshowsPrec p (a :*: b) = 
    gshowsPrec (p + 1) a . 
    showChar ' ' . 
    gshowsPrec (p + 1) b 

showsPrecDefault :: (Generic a, GShow (Rep a)) => Int -> a -> ShowS 
showsPrecDefault p = gshowsPrec p . from