2009-01-10 32 views
21

Bunun bir hata olduğunu düşünmüyorum, ancak bunun neden işe yaramadığına biraz şaşırdım. Bir bonus soru, neden e değişkeninden bahsediyor? Değişken yoktur e.Belirsiz tip değişken hatası msg

Görünüşe göre ghci 6.8'de düzgün çalışıyor, 6.10.1 kullanıyorum.

Düzenleme: Kodu en aza indirdim. Ben o kadar derlemeye çalışırken aynı hem 6.8 sonucu ve 6,10

class C a                          

foo :: C a => (a -> Int)-> Int                     
foo _ = 1                          

arg :: C a => a -> Int                       
arg _ = 2                          

bar :: Int                          
bar = foo arg 

olmasını bekliyoruz:

 
[1 of 1] Compiling Main    (/tmp/foo.hs, interpreted) 

/tmp/foo.hs:12:10: 
    Ambiguous type variable `a' in the constraint: 
     `C a' arising from a use of `arg' at /tmp/foo.hs:12:10-12 
    Probable fix: add a type signature that fixes these type variable(s) 
Failed, modules loaded: none. 
Prelude Control.Exception> 

cevap

10

Bu sorun yalnızca ghc 6.10 renkte görünür; handle tipi farklı olduğu için ghc 6.8 yinelenmemelidir edilemez:

: [email protected] 620 ; ghci 
GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help 
Loading package base ... linking ... done. 
Prelude> :m +Control.Exception 
Prelude Control.Exception> handle (\_ -> return "err") undefined 
"err" 
Prelude Control.Exception> 

Tamam belki sonunda bu hakkı elde edebilirsiniz. Bence sorun monomorphism kısıtlaması değil, Read/Show probleminin bir örneğini vurdunuz: bir tür istisnayı ele almayı teklif ediyorsun, `` tutamacın yeni sürümünde, Bir istisna türü ve sonuçta bu istisnanın türü görünmez. Yani derleyicinin, ele almaya çalıştığınız istisnası türü olan 'u bilmesinin bir yolu yoktur. Bunu yapmanın bir yolu da bir tane seçmektir.

Prelude Control.Exception> let alwaysError :: SomeException -> IO String; alwaysError = \_ -> return "err" 
Prelude Control.Exception> handle alwaysError undefined 
"err" 

arada, GHC kütüphane belgelerinde handle örnek kullanımı 6.10 altında derlemek değildir: Burada işler biraz kod. Bir hata raporu aldım.

+0

Neden derleyici hangi istisna bilmek gerekir? İşlev, sınıftaki her türünü işler. – luntain

+0

'handle' türünden dolayı; "handle" kullanımı, Exception sınıfından * bir * özel türe uygulanmalıdır. İşleyiciniz sınıftaki tüm türler için çalıştığından, derleyicinin 'handle' türüne bir ataması için bir yol yoktur. ('' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' 'Döndürür.) –

+0

Eğer ScopedTypeVariables uzantısını kullanırsanız, '' unrule '' komutunu '' ('\' _ExException) '-' 'err' 'döndürün' 'yapabilirsiniz. – porges

1

"İstisna e", "tanıtıcı" nın tür imzasından kaynaklanıyor olabilir.

The documentation diyor ki:

handle :: Exception e => (e -> IO a) -> IO a -> IO a 

ghc 6.8 yılında ben bu hatayı alamadım nedenini açıklıyor, farklı olmak için kullanılır.

handle :: (Exception -> IO a) -> IO a -> IO a 

Monomorphism kısıtlamasına giriyor gibi görünüyor. Bu "_" - Desen monomorfik olmalı (ghc 6.8 ile) veya açıkça yazılmalıdır. Bir "geçici çözüm", deseni, Haskell Raporunun belirttiği gibi "basit bir desen bağlama" teşkil ettiği bir tanımın sol tarafına koymaktır.

bu deneyin:

let f _ = return "err" 
handle f undefined 

http://www.haskell.org/haskellwiki/Monomorphism_restriction

+0

let f _ = dönüş 'err' sap f ne dersiniz aynı hatayı – luntain

+0

verir @Porges pragma {- # -XNoMonomorphismRestriction # -} – Waquo

+0

Sanırım bu, {- # LANGUAGE NoMonomorphismRestriction # -} – Waquo

3

bir geçici çözüm ghc 6.10'da Control.OldException kullanmaktır * yerine Control.Exception arasında..

2

İşleyicinize SomeException -> IO x türünü vermeyi deneyin; burada x, bir beton türüdür, örn.

import Control.Exception 
let f _ = putStrLn "error" :: SomeException -> IO() 
in handle f undefined 
11

Control.Exception.handle türüdür:

handle :: Exception e => (e -> IO a) -> IO a -> IO a 

Gördüğünüz sorun lambda ifadesi (\_ -> return "err") değil eException bir örneği olan tip e -> IO a ait olmasıdır. Çamur kadar temiz? İyi. Şimdi ben aslında yararlı olması gereken bir çözüm :)

Sadece çok olur sizin durumunuzda ErrorCall (Exception bir örneği) atar error kullanan Control.Exception.ErrorCallundefined beri e olması gerektiğini vereceğiz.

handleError :: (ErrorCall -> IO a) -> IO a -> IO a 
handleError = handle 

Esasen e ile Control.Exception.handleerror atar ne ErrorCall olarak sabit bir takma ad:

Eğer handleError gibi bir şey tanımlayabilir undefined kullanımlarını işlemek için. yılında GHCi 7.4.1 çalıştırdığınızda

Bu şuna benzer:

ghci> handleError (\_ -> return "err") undefined 
"err" 

şöyle bir handleAll fonksiyonu yazılabilir tüm istisnalar işlemek için:

handleAll :: (SomeException -> IO a) -> IO a -> IO a 
handleAll = handle 

sonuçları vardır tüm istisnaları yakalamak Control.Exception belgelerinin şu alıntılarında iyi tanımlanmıştır:

yakalamak tüm istisnalar

O SomeException türünü kullanarak, tüm özel durumları yakalamak mümkündür:

catch f (\e -> ... (e :: SomeException) ...) 

ANCAK, bu yapmak istediğim normalde değil! Örneğin, bir dosyayı okumak istediğinizi varsayalım, ancak varsa, "" içeriyormuş gibi devam edin. Tüm özel durumları yakalamak ve işleyicide ""'u döndürmek isteyebilirsiniz. Bununla birlikte, bunun her türlü istenmeyen sonuçları vardır. Örneğin, kullanıcı yalnızca C-Control'de C tuşuna basarsa, UserInterrupt istisnası yakalanır ve program, dosyanın "" içerdiği inancıyla çalışmaya devam eder. Benzer şekilde, başka bir iş parçacığı dosyayı okuma iş parçacığı öldürmeye çalışırsa, ThreadKilled istisnası göz ardı edilir.

Bunun yerine, yalnızca gerçekten istediğiniz özel durumları yakalamanız gerekir. Bu durumda, bu muhtemelen "herhangi bir IO istisnası" ndan daha spesifik olacaktır; Bir izin hatası büyük olasılıkla farklı ele alınmak isteyecektir. Bunun yerine, muhtemelen böyle bir şey isteyeyim:

e <- tryJust (guard . isDoesNotExistError) (readFile f) 
let str = either (const "") id e 

gerçekten istisna her türlü yakalamak gerekiyor özel günler vardır. Ancak, çoğu durumda, bu sadece bazı temizlik yapabilmeniz içindir; aslında istisnanın kendisi ile ilgilenmiyorsunuz.Örneğin, bir dosyayı açarsanız, dosyayı tekrar işleyip işlemeyeceğinizi, dosyanın normal şekilde işleyip işlemeyeceğini veya bir istisna atar. Bununla birlikte, bu gibi durumlarda, aslında size özel bir durum iletmeyen bracket, finally ve onException gibi işlevleri kullanabilirsiniz, ancak temizleme işlevlerini uygun noktalarda aramanız yeterlidir.

Ancak bazen gerçekten bir istisna yakalamanız ve aslında istisnanın ne olduğunu görmeniz gerekir. Bir örnek, bir programın en üst düzeyindedir, herhangi bir istisnayı yakalamak, bir log dosyasına veya ekrana yazdırmak ve sonra incelikle çıkmak isteyebilirsiniz. Bu durumlarda, SomeException türüyle catch (veya diğer istisna yakalama işlevlerinden biri) kullanabilirsiniz.

Kaynak: http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception.html#g:4