2012-10-10 30 views
5

假設我想創建一個新的數據類型並使構造函數可顯示,只能以小寫而不是大寫形式定義。例如:如何以小寫「顯示」構造函數

data Day = Monday | Tuesday | Wednesday| Thursday | Friday | Saturday | Sunday 

通過添加獲得展會,ghci的將打印他們爲 「星期一,星期二..等。」爲了得到它,以示「星期一,星期二..等」我試圖讓展會的一個特例:

import Data.Char 

strToLower :: [Char] -> [Char] 
strToLower (x:xs) = toLower x : strToLower xs 
strToLower [] = [] 

instance Show Day where 
    show d = strToLower (show d) 

這裏展示的第一次出現應指定我的新修訂的播放功能(將其稱之爲每次我打印),而對於第二個我打算通常派生版本的show,從構造函數名稱獲得一個字符串。

當然,這不起作用(循環定義),因爲ghci不知道如何讓我知道這個區別,因爲這兩個版本都需要被命名爲show,第一個是因爲這是print調用的內容,第二個是因爲它是一個預定義的haskell函數,它可以從構造函數名稱中爲我提供一個String。我試過

show d = strToLower ((showsPrec 0 d) "") 

但是這可以歸結爲同一個循環定義,至少這是我從ghci的猜測被陷在一個循環。

我明白爲什麼構造函數名稱需要以大寫字母開頭,但如果顯示小寫字母不應該是個問題,應該如何?我知道我可以單獨爲每個案例定義我的演出功能,例如show Monday = "monday"show Tuesday = "tuesday"等,但我只使用星期幾作爲一個例子在這裏,我的真正的數據類型由64個構造函數組成,所以我認爲以不同方式解決它會更優雅。

是否可以挖掘show的haskell定義並修改該代碼的副本?這是我能想到的唯一可能的解決方案,但如果可能的話,我不知道該怎麼做。可能不會。所以其他解決方案也非常受歡迎!

感謝您抽出寶貴的時間,

耶勒(Haskell的初學者)

+4

爲什麼不能寫'showDay day = map toLower。 show'並使用'showDay'而不是'show'? – dave4420

+0

除了其他的答案,它可能是值得回答你的直接問題(我怎樣才能使用派生的'show'來實現我自己的'show'?),答案是「你不能」。 Haskell的一個基本規則是每個類對於一個給定的類型可能具有最多的一個實例。 –

回答

9

實際上,你可以做到這一點使用的TypeableData類。

要做到這一點,你需要的DeriveDataTypeable擴展,將其與-XDeriveDataTypeable或通過將以下行的文件定義你的類型開始:

{-# LANGUAGE DeriveDataTypeable #-} 

現在,您可以導入所需的模塊:

import Data.Data 
import Data.Typeable 

並從中獲得TypeableData

data Day = Monday | Tuesday | Wednesday| Thursday | Friday | Saturday | Sunday 
    deriving (Typeable, Data) 

現在你可以使用toConstr得到一個構造函數表示:

instance Show Day where 
    show = strToLower . showConstr . toConstr 

但看您是否確實想要其他的答案,而不是簡單地使用showDay功能或您自己的類型類,而不是。

+0

+1謝謝..我沒想到可以這樣做.. – Satvik

+0

非常感謝!我更喜歡這種解決方案,因爲它很容易,它保留了「可展示」的純粹概念,而不必訴諸於「假」(我)的展示功能。再次感謝! – user1734761

+0

但是,我不會構建這樣的'Show'實例,因爲它的輸出不是有效的Haskell代碼。但是,這是定義showDay或定製類型類顯示函數+1的非常好的方法。 - 在一個不相關的說明中,寫'f $ g $ x'形式的表達式是[種類不贊成的](http://stackoverflow.com/a/8618901/745903),使用等效的f。 g $ x'代替(所以在這種情況下'show d = strToLower。showConstr $ toConstr d')。 – leftaroundabout

3

嘛不知道如果你能做到,對於相同的數據類型,但有解決方法,我可以看到的是把它包裝成一個NEWTYPE爲

newtype D = D Day 
instance Show D where 
    show (D d) = strToLower $ show d 

現在你可以使用類型D代替Day

+0

......不得不寫'(D星期一)'而不是'星期一'。 (不要說這是一個壞主意,必然只是它有其缺點。) – dave4420

+0

@ dave4420那麼他現在可以定義一些其他功能而不是'show',但'show'實例可能被其他庫函數使用,所以他不能修改那個。它是我談論的權衡,這就是爲什麼我說這是一個解決方法,有一些成本來支付寫這些額外的構造函數。 – Satvik

6

Show類的實例應該以這樣的方式工作,即您可以複製粘貼其輸出並將其用作Haskell代碼。如果你現在有小寫構造函數,這些將不會如此工作。他們將與newtype方式工作,

data DayInternal = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday 

newtype Day = Day DayInternal 
monday = Day Monday 
tuesday = Day Tuesday 
wednesday = Day Wednesday 
thursday = Day Thursday 
friday = Day Friday 
saturday = Day Saturday 
sunday = Day Sunday 

instance Show Day where 
    show (Day d) = strToLower $ show d 

當然,這留給你,你可能不喜歡冗餘。你可以使用Template Haskell自動構建它,但我懷疑這是否真的值得。

我真的認爲,你想要的不是一個Show實例,而是某種漂亮的打印。你可以推出自己的

class MyNiceShow s where 
    myNiceShow :: s -> String 

data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday 
     deriving (Show) 

instance MyNiceShow Day where 
    myNiceShow d = strToLower $ show d 
+0

我不認爲編寫所有這些函數(即使通過TH)將有任何用處,因爲您無法在它們上進行模式匹配,我認爲大部分編寫這些構造函數都將用於模式匹配。 – Satvik

+0

另外添加一個新的類型類只是爲了編寫show是很沒用的,因爲你必須爲其他類定義實例或者直接使用這個函數來簡化dave建議的內容(寫一個myshow函數)。 – Satvik

+1

不,你可以使用'ShowShow'來定義'MyNiceShow',用於所有其他類型(使用#OverlappinInstances,但是嘿..)。 – Landei

相關問題