-XAllowAmbiguousTypes ne zaman uygundur?


212

Geçenlerde bir gönderdiniz soru hakkında sözdizimsel-2,0 tanımına ilişkin share. GHC 7.6'da şu şekilde çalıştım :

{-# 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

Ancak, GHC 7.8 -XAllowAmbiguousTypesbu imzayla derlemek istiyor . Alternatif olarak, yerine fiile

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

fundep'in ima ettiği türdür SyntacticN. Bu uzantıdan kaçınmamı sağlıyor. Tabii ki bu

  • zaten büyük bir imzayı eklemek için çok uzun bir tür
  • manuel olarak türetmek için yorucu
  • fundep nedeniyle gereksiz

Sorularım:

  1. Bu kabul edilebilir bir kullanımı -XAllowAmbiguousTypesmı?
  2. Genel olarak, bu uzantı ne zaman kullanılmalıdır? Burada bir cevap "neredeyse hiç iyi bir fikir değildir" anlamına gelir.
  3. Belgeleri okumama rağmen , yine de bir kısıtlamanın belirsiz olup olmadığına karar vermede sorun yaşıyorum. Özellikle, Data.Syntactic.Sugar'daki bu işlevi göz önünde bulundurun:

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

    Bana öyle geliyor ki fi(ve muhtemelen sup) burada belirsiz olmalı, ancak uzantı olmadan derleniyor. Neden belli sugarSymbelirsiz share? Yana sharebir uygulamadır sugarSym, sharekısıtlamaları tüm düz geliyor sugarSym.


4
Belirsiz tip değişkenlerini içeren ve içermeyen sugarSym Let, sadece türünü kullanamamanızın bir nedeni var mı (SyntacticN f (ASTF sup a -> ASTF sup (a -> b) -> ASTF sup b), Let :<: sup) => f?
kosmikus

3
@kosmikus Sorrt Yanıtlamak çok uzun sürdü. Bu kod için türetilmiş imzası ile derleme değil share, ama does sorudaki imzaların ya kullanıldığında derleme. Ayrıca soru bir önceki gönderinin
crockeea

3
Tanımsız davranış muhtemelen en uygun terim değildir. Sadece bir programa dayanarak anlamak zor. Sorun, aldatıcılık ve GHCI'nin programınızdaki türleri kanıtlayamamasıdır. Sadece bu konuda ilginizi çekebilecek uzun bir tartışma var. haskell.org/pipermail/haskell-cafe/2008-April/041397.html
BlamKiwi

6
(3) 'e gelince, bu tip SyntacticN (yani, f - »fi) ve ApplySym (özellikle fi -> sig, sup) tanımındaki Fonksiyonel Bağımlılıklar nedeniyle belirsiz değildir. Bu itibaren, şunu alır ftek başına yeterli tamamen belirsizliği olduğunu sig, five sup.
user2141650

3
@ user2141650 Üzgünüz, cevap vermesi çok uzun sürdü. Üzerinde fundep söylüyorsun SyntacticNyapar fiiçinde kesin sugarSym, ama o zaman neden için de geçerlidir aynı değildir fide share?
crockeea

Yanıtlar:


12

İmzası sugarSymtam olarak bu tür adları kullanan herhangi bir sözdizim yayınlanmış sürümünü görmüyorum , bu yüzden hala bu adları kullanan son sürüm olan 8cfd02 ^ 'de geliştirme dalını kullanacağım .

Öyleyse, GHC neden fisizin tip imzanızdan şikayet ediyor, ancak neden imzanızdan şikayet ediyor sugarSym? Bağlandığınız belgeler, bir türün, diğer belirsiz olmayan türlerden başka türlü belirsiz türler çıkarmak için işlevsel bağımlılıklar kullanmadığı sürece, kısıtlamanın sağında görünmüyorsa belirsiz olduğunu açıklar. Şimdi iki fonksiyonun bağlamlarını karşılaştıralım ve fonksiyonel bağımlılıkları araştıralım.

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

Yani için sugarSym, olmayan belirsiz türleridir sub, sigve f, ve olanlardan biz yani bağlamda kullanılan tüm diğer türleri belirsizliği amacıyla fonksiyonel bağımlılıkları takip etmek gerekir supve fi. Ve aslında, bizim f -> internalfonksiyonel bağımlılık SyntacticNbizim fanlamını belirsizleştirmek için kullanır fi, ve daha sonra kullanımdaki f -> sig symfonksiyonel bağımlılık ApplySymbizim de belirsizleştirmek fiiçin yeni de ayrışmış sup(ve sigzaten belirsiz olmayan) kullanır. Bu da neden uzantı sugarSymgerektirmediğini açıklıyor AllowAmbiguousTypes.

Şimdi bakalım sugar. Ilk şey gözüme derleyici olmasıdır değil örneklerini çakışması konusunda oldukça belirsiz bir türü hakkında şikayetçi ama:

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

Bu yüzden doğru okuyorsam, GHC, türlerinizin belirsiz olduğunu düşünmez, aksine, türlerinizin belirsiz olup olmadığını kontrol ederken, GHC farklı, ayrı bir sorunla karşılaştı. Daha sonra size GHC'ye belirsizlik kontrolü yapmamasını söylerseniz, bunun ayrı bir sorunla karşılaşmayacağını söyler. Bu, AllowAmbiguousTypes'i etkinleştirmenin neden kodunuzun derlenmesine izin verdiğini açıklar.

Ancak, örtüşen örneklerle ilgili sorun devam etmektedir. GHC ( SyntacticN f five SyntacticN (a -> f) ...) tarafından listelenen iki örnek birbiriyle çakışır. Garip bir şekilde, bunlardan birincisi şüpheli olan başka bir örnekle çakışmalıdır. Peki ne [overlap ok]demek?

Syntactic'in OverlappingInstances ile derlendiğinden şüpheleniyorum. Ve koda bakarak , gerçekten de öyle.

Biraz deneme yaparak, birinin diğerinden kesinlikle daha genel olduğu açık olduğunda GHC örtüşen örneklerle iyi görünüyor:

{-# 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])

Ancak GHC, ikisi de açıkça diğerinden daha iyi olmadığında örtüşen örneklerle iyi değildir:

{-# 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])

Kişisel tipi imza kullandığı SyntacticN (a -> (a -> b) -> b) five ne SyntacticN f fide SyntacticN (a -> f) (AST sym (Full ia) -> fi)diğerinden daha iyi bir seçimdir. Tür imzanızın bu kısmını SyntacticN a fiveya olarak değiştirirsem SyntacticN (a -> (a -> b) -> b) (AST sym (Full ia) -> fi), GHC artık çakışmadan şikayet etmez.

Ben siz olsaydım , bu iki olası örneğin tanımına bakar ve bu iki uygulamadan birinin istediğiniz biri olup olmadığını tespit ederdim .


2

Ben bununla AllowAmbiguousTypeskullanım için çok uygun olduğunu keşfettim TypeApplications. Fonksiyonunu düşünün natVal :: forall n proxy . KnownNat n => proxy n -> Integergelen GHC.TypeLits .

Bu işlevi kullanmak için yazabilirim natVal (Proxy::Proxy5). Alternatif bir stil kullanımı etmektir TypeApplications: natVal @5 Proxy. Türü Proxy, tür uygulaması tarafından çıkarılır ve her aradığınızda yazmak zor olabilir natVal. Böylece şunları etkinleştirebilir AmbiguousTypesve yazabiliriz:

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

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

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

Ancak, bir kez belirsizleştiğinizde geri dönemeyeceğinizi unutmayın !

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.