खराब और आसान ऐसा करने का तरीका है और अच्छा लेकिन कठिन तरीका है। Silvio Mayolo के रूप में कहा गया है कि आप इस तरह के फ़ंक्शन को लिखने के लिए TemplateHaskell
का उपयोग कर सकते हैं। इस तरह से कठिन और जटिल तरीका है।
{-# LANGUAGE CPP #-}
#define MY_OWN_CLASS (Eq, Ord, Show, Read, Data, SymWord, HasKind, SMTValue)
data X = A | B | C
deriving MY_OWN_CLASS
अद्यतन (2016/07/17): विचारों वें समाधान
की & स्केच समाधान के स्केच शुरू करने से पहले मैं उदाहरण देकर स्पष्ट करना होगा क्यों यह कठिन है आसान तरीका इस तरह सी पूर्वप्रक्रमक उपयोग करने के लिए है टी के साथ करने के लिए deriving
-clause कुछ स्वतंत्र खंड नहीं है, यह data
घोषणा का हिस्सा है ताकि आप दुर्भाग्यवश deriving
के अंदर केवल भाग को एन्कोड नहीं कर सकें। किसी भी TH कोड को लिखने का सामान्य दृष्टिकोण ब्रैकेट पर runQ
कमांड का उपयोग करना है ताकि यह देखने के लिए कि आपको अंत में क्या लिखना चाहिए। इस तरह:
ghci> :set -XTemplateHaskell
ghci> :set -XQuasiQuotes
ghci> import Language.Haskell.TH
ghci> runQ [d|data A = B deriving (Eq, Show)|]
[ DataD
[]
A_0
[]
Nothing
[ NormalC B_1 [] ]
[ ConT GHC.Classes.Eq , ConT GHC.Show.Show ]
]
अब आप देख deriving
के लिए उस प्रकार कक्षाएं DataD
के अंतिम तर्क के रूप में निर्दिष्ट कर रहे हैं - डेटा घोषणा - निर्माता। आपकी समस्या के लिए कामकाज -XStadandaloneDeriving
extension का उपयोग करना है। यह deriving
जैसा है लेकिन बहुत शक्तिशाली हालांकि बहुत अधिक वर्बोज़ है। फिर से, देखने के लिए, वास्तव में क्या आप उत्पन्न करना चाहते हैं, बस runQ
का उपयोग करें:
ghci> data D = T
ghci> :set -XStandaloneDeriving
ghci> runQ [d| deriving instance Show D |]
[ StandaloneDerivD [] (AppT (ConT GHC.Show.Show) (ConT Ghci5.D)) ]
आप StandaloneDerivD
और अन्य निर्माताओं के सीधे उपयोग कर सकते हैं या सिर्फ [d|...|]
-brackets का उपयोग हालांकि वे अधिक जादू है, लेकिन वे तुम्हें Dec
की सूची दे (घोषणाओं)। आप कई घोषणाओं उत्पन्न करने के लिए चाहते हैं तो आपको आप इस तरह कार्य लिखना चाहिए:
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE StandaloneDeriving #-}
module Deriving where
import Language.Haskell.TH
boilerplateAnnigilator :: Name -> Q [Dec]
boilerplateAnnigilator typeName = do
let typeCon = conT typeName
[d|deriving instance Show $(typeCon)
deriving instance Eq $(typeCon)
deriving instance Ord $(typeCon)
|]
संक्षिप्त ट्यूटोरियल can be found here।
और फिर आप एक और फ़ाइल में उपयोग कर सकते हैं (इस वें सीमा मंचन प्रतिबंध कहा जाता है: आप मैक्रो एक फ़ाइल में परिभाषित करना चाहिए, लेकिन आप एक ही फाइल में इसका इस्तेमाल नहीं कर सकते हैं) इस तरह:
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
import Deriving
data X = A | B | C
boilerplateAnnigilator ''X
आप अन्य प्रकार कक्षाएं आप boilerplateAnnigilator
समारोह के अंदर चाहते रखना चाहिए। लेकिन यह दृष्टिकोण केवल गैर-पैरामीट्रिज्ड वर्ग के लिए काम करता है। आप data MyData a = ...
है तो स्टैंडअलोन पाने तरह दिखना चाहिए:
deriving instance Eq a => MyData a
और अगर आप parametrized कक्षाओं के लिए अपने वें मैक्रो काम के साथ-साथ हों, तो आपको मूल रूप से GHC संकलक के पूरे तर्क बात का अनुमान लगाना है कि क्या प्रकार प्रकार से लागू करना चाहिए चर या नहीं और उस पर निर्भर उदाहरण उत्पन्न करें। लेकिन यह बहुत कठिन है। मुझे लगता है कि सबसे अच्छा समाधान सिर्फ जीएचसी कंपाइलर में टिकट बनाना है और लेखकों को नामक उपनाम :)
'व्युत्पन्न' खंड वास्तव में जादू हैं। टी के बिना, मुझे डर है कि वास्तव में ऐसा करने का कोई तरीका नहीं है जिसे आप करना चाहते हैं। –
बनाने https://github.com/haskell/rfcs – baxbaxwalanuksiwe