2012-11-29 14 views
15

मैं एक typeclass कुछ कार्यान्वित कार्य करता है जो एक लागू नहीं किया गया स्थिरांक मान का उपयोग किया है कि (table) घोषित करने के लिए चाहते हैं घोषित करने के लिए:एक तरह से एक प्रकार कक्षा में एक निरंतर मूल्य

class FromRow a => StdQueries a where 
    table :: String 
    byId :: Int -> QueryM (Maybe a) 
    byId = fmap listToMaybe . queryM sql . Only 
    where sql = read $ "SELECT * FROM " ++ table ++ " WHERE id = ?" 

विचार सरल है: मैं चाहता हूँ बस table निर्दिष्ट करके इस typeclass instantiating द्वारा byId (और अन्य समान कार्य) उपलब्ध मिलती है:

instance StdQueries SomeType where 
    table = "the_constant_value_for_this_type" 

लेकिन संकलक निम्न संदेश के साथ शिकायत कर रखता है:

The class method `table' 
mentions none of the type variables of the class StdQueries a 
When checking the class method: table :: String 
In the class declaration for `StdQueries' 

वहाँ एक समस्या उस तरह के लिए किसी भी समाधान कर रहे हैं? newtype सहायता या उस तरह से कुछ भी कर सकते हैं?

उत्तर

17

सरल बात आप कर सकते हैं

class FromRow a => StdQueries a where 
    byId :: Int -> QueryM (Maybe a) 

defaultById :: FromRow a => String -> Int -> QueryM (Maybe a) 
defaultById table = fmap listToMaybe . queryM sql . Only 
    where sql = read $ "SELECT * FROM " ++ table ++ " WHERE id = ?" 

instance StdQueries SomeType where 
    byId = defaultById "the_constant_value_for_this_type" 

यह सरल है, लेकिन अगर आप एक से अधिक कार्य है कि table मूल्य पर पहुंच की आवश्यकता है, तो आप एक बार से है कि मूल्य अधिक निर्दिष्ट करना होगा।

आपको लगता है कि बच सकते हैं, और undefined और {-# LANGUAGE ScopedTypeVariables #-} इस तरह के लिए sabauma की जरूरत:

newtype Table a = Table String 

class FromRow a => StdQueries a where 
    table :: Table a 
    byId :: Int -> QueryM (Maybe a) 
    byId = defaultById table 

defaultById :: StdQueries a => Table a -> Int -> QueryM (Maybe a) 
defaultById (Table table) = fmap listToMaybe . queryM sql . Only 
    where sql = read $ "SELECT * FROM " ++ table ++ " WHERE id = ?" 

instance StdQueries SomeType where 
    table = Table "the_constant_value_for_this_type" 

यहाँ जादू defaultById के लिए प्रकार हस्ताक्षर है, जो byId मजबूर करता ही उदाहरण से table प्रदान करना है। अगर हमने defaultById :: (StdQueries a, StdQueries b) => Table a -> Int -> QueryM (Maybe b) प्रदान किया है तो defaultById अभी भी संकलित होगा, लेकिन हम अभी भी आपके प्रश्न में एक को एक ही त्रुटि संदेश प्राप्त करेंगे: संकलक अब table की परिभाषा का उपयोग करने के लिए नहीं जानता है।

Table anewtype रैपर की बजाय data संरचना बनाकर, यदि आप आवश्यक हो तो निरंतर में कई फ़ील्ड निर्दिष्ट करने के लिए इसे विस्तारित कर सकते हैं।

5

मुद्दा यह है कि table की परिभाषा कक्षा के किसी भी प्रकार के चर का उल्लेख नहीं करती है, इसलिए table का उपयोग करने के लिए कोई भी तरीका नहीं होगा।

{-# LANGUAGE ScopedTypeVariables #-} 
class FromRow a => StdQueries a where 
    table :: a -> String 
    byId :: Int -> QueryM (Maybe a) 
    byId = fmap listToMaybe . queryM sql . Only 
    where sql = read $ "SELECT * FROM " ++ table (undefined :: a) ++ " WHERE id = ?" 

instance StdQueries SomeType where 
    table = const "the_constant_value_for_this_type" 

जो तुम तो

table (undefined :: SomeType) == "the_constant_value_for_this_type" 

नहीं के माध्यम से इस्तेमाल कर सकते हैं कि मैं वास्तव में यह कर की सिफारिश करेंगे: एक (वैसे hackish) समाधान की तरह कुछ हो सकता है।

+4

इसमें कोई गड़बड़ नहीं है, बहुत से प्रकार के वर्ग इस तरह से करते हैं। – leftaroundabout

+0

कृपया इसे और अधिक पठनीय बनाने के लिए अपना कोड प्रारूपित करें; भी, क्या यह वास्तव में काम करता है? ऐसा लगता है कि आप अब 'टेबल' को एक फ़ंक्शन बना रहे हैं, लेकिन आप इसे 'sql = ...' भाग में इस तरह से उपयोग नहीं कर रहे हैं। – ErikR

+0

तालिका का प्रकार 'ए -> स्ट्रिंग' है और 'स्ट्रिंग' नहीं है तो आप इसे कैसे जोड़ रहे हैं? – Satvik

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