जब -XAllowAmbiguousTypes उपयुक्त है?


212

मैं हाल ही में एक पोस्ट किया है प्रश्न के बारे में वाक्यात्मक-2.0 की परिभाषा के बारे में share। मैंने जीएचसी 7.6 में यह काम किया है :

{-# LANGUAGE GADTs, TypeOperators, FlexibleContexts #-}

import Data.Syntactic
import Data.Syntactic.Sugar.BindingT

data Let a where
    Let :: Let (a :-> (a -> b) :-> Full b)

share :: (Let :<: sup,
          sup ~ Domain b, sup ~ Domain a,
          Syntactic a, Syntactic b,
          Syntactic (a -> b),
          SyntacticN (a -> (a -> b) -> b) 
                     fi)
           => a -> (a -> b) -> b
share = sugarSym Let

हालाँकि, GHC 7.8 -XAllowAmbiguousTypesउस हस्ताक्षर को संकलित करना चाहता है। वैकल्पिक रूप से, मैं के fiसाथ बदल सकते हैं

(ASTF sup (Internal a) -> AST sup ((Internal a) :-> Full (Internal b)) -> ASTF sup (Internal b))

यह फंड किसके द्वारा निहित प्रकार है SyntacticN। यह मुझे विस्तार से बचने की अनुमति देता है। बेशक यह है

  • एक पहले से बड़े हस्ताक्षर को जोड़ने के लिए एक बहुत लंबा प्रकार
  • मैन्युअल रूप से प्राप्त करने के लिए थकाऊ
  • फंड की वजह से अनावश्यक

मेरे प्रश्न हैं:

  1. क्या यह स्वीकार्य उपयोग है -XAllowAmbiguousTypes?
  2. सामान्य तौर पर, इस विस्तार का उपयोग कब किया जाना चाहिए? यहां एक उत्तर बताता है कि "यह लगभग कभी अच्छा विचार नहीं है"।
  3. हालाँकि मैंने डॉक्स पढ़ा है , फिर भी मुझे यह तय करने में परेशानी हो रही है कि कोई बाधा अस्पष्ट है या नहीं। विशेष रूप से, Data.Syntactic.Sugar के इस फ़ंक्शन पर विचार करें:

    sugarSym :: (sub :<: AST sup, ApplySym sig fi sup, SyntacticN f fi) 
             => sub sig -> f
    sugarSym = sugarN . appSym

    यह मुझे प्रतीत होता है कि fi(और संभवतः sup) यहां अस्पष्ट होना चाहिए, लेकिन यह विस्तार के बिना संकलन करता है। sugarSymजबकि असंदिग्ध क्यों है share? के बाद shareसे एक आवेदन है sugarSym, shareसभी बाधाओं से सीधे आते हैं sugarSym


4
क्या कोई कारण है कि आप सिर्फ इसके लिए अनुमानित प्रकार का उपयोग नहीं कर सकते हैं sugarSym Let, जिसमें (SyntacticN f (ASTF sup a -> ASTF sup (a -> b) -> ASTF sup b), Let :<: sup) => fअस्पष्ट प्रकार के चर शामिल नहीं हैं?
कोसमिकस

3
@kosmikus Sorrt को प्रतिक्रिया देने में इतना समय लगा। इस कोड के लिए अनुमान हस्ताक्षर के साथ संकलन नहीं करता है share, लेकिन जब प्रश्न में उल्लिखित हस्ताक्षर का उपयोग किया जाता है, तो संकलन करता है। आपसे पिछली पोस्ट
crockeea

3
अपरिभाषित व्यवहार शायद सबसे उपयुक्त शब्द नहीं है। यह सिर्फ एक कार्यक्रम के आधार पर समझना मुश्किल है। समस्या विकलागता है और जीएचसीआई आपके कार्यक्रम के प्रकारों को साबित करने में सक्षम नहीं है। एक लंबी चर्चा है जो आपको इस विषय पर दिलचस्पी ले सकती है। haskell.org/pipermail/haskell-cafe/2008-April/041397.html
BlamKiwi

6
(3) के रूप में, SyntacticN (यानी, f - »Fi) और ApplySym (विशेष रूप से, Fi -> sig, sup) की परिभाषा में कार्यात्मक निर्भरता के कारण वह प्रकार अस्पष्ट नहीं है। कि से, आप मिल fअकेली है पर्याप्त करने के लिए पूरी तरह से स्पष्ट करने sig, fiऔर sup
user2141650

3
@ user2141650 खेद है कि उत्तर देने में इतना समय लगा। आप पर fundep कह रहे हैं SyntacticNबनाता है fiमें स्पष्ट sugarSymहै, लेकिन फिर क्यों के लिए सच में ही नहीं है fiमें share?
क्रॉकिया

जवाबों:


12

मुझे वाक्य-रचना का कोई प्रकाशित संस्करण दिखाई नहीं देता है, जिसके हस्ताक्षर sugarSymउन सटीक प्रकार नामों का उपयोग करते हैं, इसलिए मैं अंतिम संस्करण 8cfd02 ^ पर विकास शाखा का उपयोग करूंगा , जो अभी भी उन नामों का उपयोग करता है।

तो, जीएचसी fiआपके प्रकार के हस्ताक्षर के बारे में शिकायत क्यों करता है लेकिन किसके लिए नहीं sugarSym? आपके द्वारा जोड़ा गया दस्तावेज़ यह बताता है कि एक प्रकार अस्पष्ट है यदि यह बाधा के दाईं ओर दिखाई नहीं देता है, जब तक कि बाधा अन्य गैर-अस्पष्ट प्रकारों से अन्यथा अस्पष्ट प्रकार का अनुमान लगाने के लिए कार्यात्मक निर्भरता का उपयोग नहीं कर रही है। तो आइए दोनों कार्यों के संदर्भों की तुलना करें और कार्यात्मक निर्भरताओं की तलाश करें।

class ApplySym sig f sym | sig sym -> f, f -> sig sym
class SyntacticN f internal | f -> internal

sugarSym :: ( sub :<: AST sup
            , ApplySym sig fi sup
            , SyntacticN f fi
            ) 
         => sub sig -> f

share :: ( Let :<: sup
         , sup ~ Domain b
         , sup ~ Domain a
         , Syntactic a
         , Syntactic b
         , Syntactic (a -> b)
         , SyntacticN (a -> (a -> b) -> b) fi
         )
      => a -> (a -> b) -> b

इसलिए sugarSym, गैर-अस्पष्ट प्रकार हैं sub, sigऔर fउन लोगों से, जिन्हें हम संदर्भ में उपयोग किए जाने वाले अन्य सभी प्रकारों को अलग करने के लिए कार्यात्मक निर्भरता का पालन करने में सक्षम होना चाहिए, supऔर fi। और वास्तव में, f -> internalमें कार्यात्मक निर्भरता SyntacticNहमारे उपयोग करता है fहमारे को स्पष्ट करने के लिए fi, और उसके बाद f -> sig symमें कार्यात्मक निर्भरता ApplySymका उपयोग करता है हमारे नव disambiguated fiको स्पष्ट करने के लिए sup(और sigहै, जो पहले से ही गैर अस्पष्ट था)। तो यह बताता है कि विस्तार की sugarSymआवश्यकता क्यों नहीं है AllowAmbiguousTypes

आइए अब नजर डालते हैं sugar। पहली बात जो मैंने नोटिस की है कि कंपाइलर अस्पष्ट प्रकार के बारे में शिकायत नहीं कर रहा है, बल्कि उदाहरणों को ओवरलैप करने के बारे में है:

Overlapping instances for SyntacticN b fi
  arising from the ambiguity check for share
Matching givens (or their superclasses):
  (SyntacticN (a -> (a -> b) -> b) fi1)
Matching instances:
  instance [overlap ok] (Syntactic f, Domain f ~ sym,
                         fi ~ AST sym (Full (Internal f))) =>
                        SyntacticN f fi
    -- Defined in ‘Data.Syntactic.Sugar’
  instance [overlap ok] (Syntactic a, Domain a ~ sym,
                         ia ~ Internal a, SyntacticN f fi) =>
                        SyntacticN (a -> f) (AST sym (Full ia) -> fi)
    -- Defined in ‘Data.Syntactic.Sugar’
(The choice depends on the instantiation of b, fi’)
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes

इसलिए अगर मैं यह सही पढ़ रहा हूं, तो ऐसा नहीं है कि जीएचसी को लगता है कि आपके प्रकार अस्पष्ट हैं, बल्कि यह भी है कि यह जांचते समय कि आपके प्रकार अस्पष्ट हैं, जीएचसी को एक अलग, अलग समस्या का सामना करना पड़ा। यह तब आपको बता रहा है कि यदि आपने GHC को अस्पष्टता जांच नहीं करने के लिए कहा है, तो उसे उस अलग समस्या का सामना नहीं करना पड़ेगा। यह बताता है कि AllowAmbiguousTypes को सक्षम करना आपके कोड को संकलित करने की अनुमति क्यों देता है।

हालांकि, अतिव्यापी उदाहरणों के साथ समस्या बनी हुई है। जीएचसी ( SyntacticN f fiऔर SyntacticN (a -> f) ...) द्वारा सूचीबद्ध दो उदाहरण एक दूसरे के साथ ओवरलैप करते हैं। अजीब तरह से, ऐसा लगता है कि इनमें से पहले को किसी अन्य उदाहरण के साथ ओवरलैप करना चाहिए, जो संदिग्ध है। और क्या करता है[overlap ok] मतलब है?

मुझे संदेह है कि Syntactic OverlappingInstances के साथ संकलित है। और कोड को देखते हुए , वास्तव में यह करता है।

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

{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}

class Foo a where
  whichOne :: a -> String

instance Foo a where
  whichOne _ = "a"

instance Foo [a] where
  whichOne _ = "[a]"

-- |
-- >>> main
-- [a]
main :: IO ()
main = putStrLn $ whichOne (undefined :: [Int])

लेकिन जीएचसी ओवरलैपिंग उदाहरणों के साथ ठीक नहीं है जब न तो स्पष्ट रूप से दूसरे की तुलना में बेहतर फिट है:

{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}

class Foo a where
  whichOne :: a -> String

instance Foo (f Int) where  -- this is the line which changed
  whichOne _ = "f Int"

instance Foo [a] where
  whichOne _ = "[a]"

-- |
-- >>> main
-- Error: Overlapping instances for Foo [Int]
main :: IO ()
main = putStrLn $ whichOne (undefined :: [Int])

आपके प्रकार के हस्ताक्षर का उपयोग करता है SyntacticN (a -> (a -> b) -> b) fi, और न SyntacticN f fiही SyntacticN (a -> f) (AST sym (Full ia) -> fi)अन्य की तुलना में बेहतर फिट है। अगर मैं आपके प्रकार के उस हिस्से को SyntacticN a fiया तो बदल देता हूँ याSyntacticN (a -> (a -> b) -> b) (AST sym (Full ia) -> fi) , तो GHC अब ओवरलैप के बारे में शिकायत नहीं करता है।

यदि मैं आप थे, तो मैं उन दो संभावित उदाहरणों की परिभाषा को देखूंगा और यह निर्धारित करूंगा कि क्या उन दो कार्यान्वयनों में से एक आप चाहते हैं।


2

मुझे पता चला है कि AllowAmbiguousTypesयह उपयोग के लिए बहुत सुविधाजनक है TypeApplicationsGHC.TypeLitsnatVal :: forall n proxy . KnownNat n => proxy n -> Integer से फ़ंक्शन पर विचार करें ।

इस फ़ंक्शन का उपयोग करने के लिए, मैं लिख सकता था natVal (Proxy::Proxy5)। एक वैकल्पिक शैली उपयोग करने के लिए है TypeApplications: natVal @5 Proxy। प्रकार के Proxyप्रकार के आवेदन से अनुमान लगाया जाता है, और हर बार जब आप कॉल करते हैं तो इसे लिखना कष्टप्रद होता है natVal। इस प्रकार हम सक्षम AmbiguousTypesऔर लिख सकते हैं :

{-# Language AllowAmbiguousTypes, ScopedTypeVariables, TypeApplications #-}

ambiguousNatVal :: forall n . (KnownNat n) => Integer
ambiguousNatVal = natVal @n Proxy

five = ambiguousNatVal @5 -- no `Proxy ` needed!

हालाँकि, ध्यान दें कि एक बार अस्पष्ट जाने के बाद, आप वापस नहीं जा सकते हैं !

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.