2014-04-15 5 views
9

मैं प्रकार की एक समारोह के एक बुरी तरह गैर पैरामीट्रिक संस्करण लिखने के लिएबंद प्रकार के परिवारों पर बाधाएं?

pretty :: (Show a) => a -> Text 

ऐसी है कि

pretty :: Text -> Text = id 
pretty :: String -> Text = T.pack 
pretty :: (Show a) => a -> Text = T.pack . show 

तो विचार है कि कुछ भी पहले से ही एक Show उदाहरण है कि चालू किया जा सकता है करना चाहते हैं Text और String को छोड़कर, जिसे हम विशेष मामले चाहते हैं, को छोड़कर show द्वारा "सुंदर" Text में।

निम्नलिखित कोड काम करता है:

{-# LANGUAGE TypeFamilies #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, FlexibleContexts #-} 
{-# LANGUAGE DataKinds, ConstraintKinds #-} 
module Pretty (pretty) where 

import Data.Text (Text) 
import qualified Data.Text as T 

type family StringLike a :: Bool where 
    StringLike String = True 
    StringLike Text = True 
    StringLike a = False 

class (b ~ StringLike a) => Pretty' a b where 
    pretty' :: a -> Text 

instance Pretty' String True where 
    pretty' = T.pack 

instance Pretty' Text True where 
    pretty' = id 

instance (Show a, StringLike a ~ False) => Pretty' a False where 
    pretty' = T.pack . show 

type Pretty a = (Pretty' a (StringLike a)) 

pretty :: (Pretty a) => a -> Text 
pretty = pretty' 

और यह pretty समारोह के अलावा कुछ निर्यात के बिना इस्तेमाल किया जा सकता।

हालांकि, मैं pretty के लिए प्रकार हस्ताक्षर के बारे में भी खुश नहीं हूँ:

pretty :: (Pretty a) => a -> Text 

मुझे लगता है कि जब से StringLike एक बंद प्रकार परिवार है, वहाँ एक रास्ता GHC यह पता लगाने के लिए किया जाना चाहिए कि अगर केवल (Show a) रखती है, (Pretty a) पहले से ही संतुष्ट हो जाता है, के बाद से:

1. The following hold trivially just by substituting the results of applying StringLike: 
(StringLike String ~ True, Pretty' String True) 
(StringLike Text ~ True, Pretty' Text True) 

2. For everything else, we *also* know the result of applying StringLike: 
(Show a, StringLike a ~ False) => (Pretty' a (StringLike a)) 

वहाँ इस के GHC को समझाने के लिए कोई तरीका है?

+0

ए 'हा हा हा हार्ट गंभीर' विचार सिर्फ मेरे लिए हुआ है जो 'प्रीलूड' योग्यता आयात करने के लिए है, और 'सुंदर' को 'शो' का नाम बदलना है ... – Cactus

+2

"मुझे लगता है कि चूंकि स्ट्रिंगलाइक एक बंद प्रकार का परिवार है, इसलिए जीएचसी को यह पता लगाने का एक तरीका होना चाहिए कि अगर केवल (दिखाएं) धारण करता है," मुझे लगता है कि निम्नलिखित एक बड़ी समस्या है: 'स्ट्रिंगलाइक' एक तरह का प्रकार पैदा करता है (-लिफ्ट) 'बूल', 'शो' एक तरह का प्रकार 'प्रतिबंध' पैदा करता है। यह सिर्फ इतना नहीं है कि जीएचसी रिश्ते को समझ में नहीं आता है; वे वास्तव में तर्क के विभिन्न कानूनों का पालन करते हैं। उठाए गए 'बूल' के साथ, आप बहिष्कृत मध्य के कानून को मानते हैं, लेकिन 'प्रतिबंध' के साथ, आप उस पर भरोसा नहीं कर सकते हैं। –

उत्तर

5

मुझे लगता है कि जब से StringLike एक बंद प्रकार परिवार है, वहाँ एक रास्ता GHC यह पता लगाने के लिए कि अगर केवल (Show a) रखती है, (Pretty a) पहले से ही संतुष्ट है

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

type family IsInt a :: Bool where 
    IsInt Int = True 
    IsInt a = False 
class (b ~ IsInt a) => TestInt a b where 
    isInt :: a -> Bool 
instance TestInt Int True where 
    isInt _ = True 
instance (IsInt a ~ False) => TestInt a False where 
    isInt _ = False 

को परिभाषित करने पर विचार करें, GHC () से TestInt a को पूरा करने के लिए सक्षम होना चाहिए। दूसरे शब्दों में, हम किसी दिए गए प्रकार के लिए परीक्षण करने में सक्षम होना चाहिए चाहे वह इंट के बराबर हो। यह स्पष्ट रूप से असंभव है।

इसी तरह, Show a शब्दकोश एक समारोह a -> ShowS के समतुल्य है। आप निर्णय लेने में सक्षम कैसे होंगे, केवल यह देखते हुए कि क्या तर्क StringLike है?

+1

"दूसरे शब्दों में, हमें किसी दिए गए प्रकार के लिए परीक्षण करने में सक्षम होना चाहिए चाहे वह' Int' के बराबर हो। यह स्पष्ट रूप से असंभव है। " क्या यह? क्या हमें पहले से इसकी आवश्यकता नहीं है एकीकरण टाइप करें? मुझे यहां क्या समझ नहीं आ रहा है? –

+0

तो मूल रूप से आपका मुद्दा यह है कि हम केवल कुछ (अर्थात् एक) दिखा सकते हैं (> एक ए) => (सुंदर ए) ', कुछ अर्थों में, गैर-रचनात्मक रूप से? – Cactus

+0

http://hackage.haskell.org/package/base-4.7.0.0/candidate/docs/Data-Type-Equality.html#t:-61--61- के साथ 'IsInt' पहले से ही संभव नहीं है? – copumpkin

2

शायद मैंने आपके लक्ष्य को गलत समझा लेकिन यह आपके इच्छित प्रकार को पाने के लिए बहुत सारे काम की तरह लगता है।

{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, UndecidableInstances, IncoherentInstances #-} 
module Prettied where 

import Data.Text (Text, pack) 

class Pretty a where pretty :: a -> Text 

instance   Pretty Text where pretty = id 
instance   Pretty String where pretty = pack 
instance Show a => Pretty a  where pretty = pack . show 

यह लग सकता है जबकि उस pretty, प्रकार Pretty a => a -> Text होना चाहिए की वजह से IncoherentInstances यह वास्तव में प्रकार Show a => a -> Text होगा। यह शायद अपने मॉड्यूल में होना चाहिए क्योंकि IncoherentInstances सक्षम करना उन चीजों में से एक है जो वैध कोड तोड़ सकते हैं।

+6

मैं दृढ़ता से 'इनकोइन्टेंट इंस्टेंस' के उपयोग के खिलाफ सलाह दूंगा। इस परिभाषा के साथ, 'सुंदर" foo "' 'foo' 'में परिणाम। लेकिन अगर आप 'pretty2 x = pretty x' जोड़ते हैं, तो 'pretty2" foo "' \ "foo \" "' में परिणाम। बहुत मजबूत या अनुमानित नहीं है। – kosmikus

+2

हाँ, लक्ष्य यह है कि बिना किसी चीज के 'इनकोइन्टेंट इंस्टेंस' या 'अपरिवर्तनीय इंस्टेंस' के बिना ऐसा करना है। – Cactus

+3

बस 'ओवरलैपिंग इंस्टेंस' यहां काम करता है। मुझे लगता है कि हम केवल एक अजीब चरण में हैं जहां हमारे पास बंद प्रकार के परिवारों के साथ जाने के लिए फ़ंक्शन-स्तरीय एनालॉग नहीं है, इसलिए हम इन प्रकार की चीजों को काफी आसानी से परिभाषित कर सकते हैं, लेकिन टाइप क्लासेस का उपयोग करना है (जो हम बंद नहीं कर सकते हैं), ओवरलैपिंग इंस्टेंस, अपरिहार्य इंस्टेंस, आदि – jberryman

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