2016-05-23 11 views
8

Haskell, bir tür aile eşleşme hatasını bildirebiliyor mu? Örneğin, kapalı bir tip ailesini kullanarakHaskell'de bir aile modeli eşleme hatası nasıl tetiklenir?

type family Testf a where 
    Testf Char = IO() 
    Testf String = IO() 

Testf Int türü sadece Testf Int olduğunu. Derleyici herhangi bir hata üretmez. Eşleşme yoksa bir tane üretmesi mümkün mü?

cevap

7

Mümkün değil. İyi nazik tipte aile uygulamaları, hataları kendileri tarafından asla tetiklemez. Bunun yerine, yalnızca bir şey için indirgenmemiş tür aile ifadelerini kullanmaya çalıştığımızda tür hataları alıyoruz.

Biz hataları biraz daha net hale getirmek için, hata mesajları tutan özel türlerinden bazıları:, GHC bir hata atar ve biz olmayan bir yazın Error msg kullanmayı deneyin her dolayısıyla mesajımızı yazdırır Şimdi

import GHC.TypeLits 

data Error (msg :: Symbol) -- a type-level error message 

type family Testf a where 
    Testf Char = IO() 
    Testf String = IO() 
    Testf x  = Error "No match for Testf" 

- tanımlanmış değer.

ghc 8.0, biz daha güzel bir şekilde mesajımızı yazdırmak için TypeError kullanabilirsiniz:

{-# language DataKinds #-} 
import GHC.TypeLits 

type family Testf a where 
    Testf Char = IO() 
    Testf String = IO() 
    Testf x  = TypeError (Text "No matching case for Testf") 

Bu basacaktır:

Notes.hs:18:5: error: … 
    • No matching case for Testf 
    • In the expression: ... 

Ancak bu yine de sadece kullanım hatası atar:

type T = Testf Int -- this typechecks 

x :: T 
x =() -- we throw error only here 
+3

GHC 8.0 hataları iyi görünmesi için özel tip denetleyicisi desteği ile TypeLits' 'böyle bir şey sunuyor:


İşte tam bir örnek kaynak dosya. – dfeuer

+2

İyi bul, buna referans ekledi. –

4

Bu, GHC'lerde 8.0'dan önce mümkün değil, ancak the (as of this writing) just-released GHC 8.0.1 ekle custom type errors için destek.

fikri sadece fonksiyonu error :: String -> a gibi, şimdi, in GHC.TypeLits, bir ile herhangi tip yaşar tipi ailesini

type family TypeError (msg :: ErrorMessage) :: k 

sahip terimi düzeyinde bir hata ile her türlü yaşar, yani hata yazın. ErrorMessage tipi çok basit:

data ErrorMessage = Text  Symbol 
        | ShowType t 
        | ErrorMessage :<>: ErrorMessage 
        | ErrorMessage :$$: ErrorMessage 

(:<>:) yapıcı iki hata iletileri yatay birleştirir; (:$$:) yapıcısı bunları dikey olarak birleştirir. Diğer iki kurucu, söylediklerini yaparlar.

Böylece, sizin örnekte, bir TypeError ile son durumda doldurabilirsiniz; Örneğin,

type family Testf a where 
    Testf Char = IO() 
    Testf String = IO() 
    Testf a  = TypeError ( Text "‘Testf’ didn't match" 
          :$$: Text "when applied to the type ‘" 
           :<>: ShowType a :<>: Text "’") 

Ardından, doğru

testfInt :: Testf Int 
testfInt = pure() 

tanımlarken kırdığı

....hs:19:12: error: … 
    • ‘Testf’ didn't match 
     when applied to the type ‘Int’ 
    • In the expression: pure() 
     In an equation for ‘testfInt’: testfInt = pure() 
Compilation failed. 

Not hatasıyla başarısız olur tip Testf Int de pure() kullanmaya çalışıyor tanımlayan

testfInt :: Testf Int 
testfInt = undefined 

(ya da testfInt = testfInt ile benzer şekilde) iyi çalıştı.

{-# LANGUAGE UndecidableInstances, TypeFamilies, DataKinds, TypeOperators #-} 

import GHC.TypeLits 

type family Testf a where 
    Testf Char = IO() 
    Testf String = IO() 
    Testf a  = TypeError ( Text "‘Testf’ didn't match" 
          :$$: Text "when applied to the type ‘" 
           :<>: ShowType a :<>: Text "’") 

testfChar :: Testf Char 
testfChar = putStrLn "Testf Char" 

testfString :: Testf Char 
testfString = putStrLn "Testf String" 

-- Error here! 
testfInt :: Testf Int 
testfInt = putStrLn "Int"