2017-07-15 5 views
7

वहाँ एक रास्ता निम्नलिखित लिखने के लिए है:क्या इस व्युत्पन्न खंड को कम करने का कोई तरीका है?

{-# LANGUAGE DeriveDataTypeable #-} 
{-# LANGUAGE DeriveAnyClass  #-} 

data X = A | B | C 
    deriving (Eq, Ord, Show, Read, Data, SymWord, HasKind, SMTValue) 

ताकि deriving खंड की तरह किसी भी तरह छोटा किया जा सकता कुछ करने के लिए, निम्न करें:

data X = A | B | C deriving MyOwnClass 

मैं वें से बचने के लिए पर अगर चाहें सभी संभव है, और मुझे एक नई कक्षा बनाने में प्रसन्नता हो रही है जिसमें सभी व्युत्पन्न वर्गों को इसके सुपर-क्लास के रूप में आवश्यक है (जैसा ऊपर MyOwnClass में है), लेकिन यह वास्तव में deriving तंत्र के साथ काम नहीं करता है। बाधा प्रकार एक्सटेंशन के साथ, मैंने पाया कि आप यह लिख सकते हैं:

type MyOwnClass a = (Eq a, Ord a, Show a, Read a, Data a, SymWord a, HasKind a, SMTValue a) 

दुर्भाग्य से, मैं नहीं डाल सकते कि deriving खंड में। ऐसा करने के लिए क्या कोई जादू है?

संपादित करें टिप्पणियों से, ऐसा लगता है कि TH यहां एकमात्र व्यवहार्य विकल्प हो सकता है। (सीपीपी मैक्रो वास्तव में ठीक नहीं है!) यदि ऐसा है, तो TH समाधान का स्केच देखना अच्छा लगेगा।

+3

'व्युत्पन्न' खंड वास्तव में जादू हैं। टी के बिना, मुझे डर है कि वास्तव में ऐसा करने का कोई तरीका नहीं है जिसे आप करना चाहते हैं। –

+2

बनाने https://github.com/haskell/rfcs – baxbaxwalanuksiwe

उत्तर

5

खराब और आसान ऐसा करने का तरीका है और अच्छा लेकिन कठिन तरीका है। 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 संकलक के पूरे तर्क बात का अनुमान लगाना है कि क्या प्रकार प्रकार से लागू करना चाहिए चर या नहीं और उस पर निर्भर उदाहरण उत्पन्न करें। लेकिन यह बहुत कठिन है। मुझे लगता है कि सबसे अच्छा समाधान सिर्फ जीएचसी कंपाइलर में टिकट बनाना है और लेखकों को नामक उपनाम :)

+0

में एक आरएफसी आप वें समाधान स्केच कर सकते हैं पर विचार करें? –

+0

@LeventErkok मैंने TH समाधान के छोटे स्केच लिखा था। अब आप देख सकते हैं कि यह कम छोटा क्यों है :) – Shersh

+0

सबसे उपयोगी लेखन के लिए धन्यवाद। यह मेरे उपयोग के मामले के लिए एक आकर्षण की तरह काम किया! बहुत सराहना की। –

संबंधित मुद्दे

 संबंधित मुद्दे