28

Bu benim -Wall kullanarak, GHC kapsamlı olmayan desenleri karşı uyarabilir anlıyoruz Why am I getting "Non-exhaustive patterns in function..." when I invoke my Haskell substring function?Haskell'de, kapsamlı olmayan modeller neden derleme zamanı hataları değildir?

bir devamı niteliğindedir.

f :: [a] -> [b] -> Int 
f [] _ = error "undefined for empty array" 
f _ [] = error "undefined for empty array" 
f (_:xs) (_:ys) = length xs + length ys 

soru GHC özgü değildir: Ben açıkça kısmi işlevi tanımlamak için her zaman mümkün olduğunu verilen varsayılan bir derleme zamanı hatası yapmıyor sebebi ne merak ediyorum.

  • kimse bu tür bir analiz gerçekleştirmek için bir Haskell derleyicisi uyulmasını istedi o ... çünkü mı?
  • Kapsamlı olmayan bir desen araması, bazı durumlar değil, bazılarını bulabilir mi?
  • Kısmen tanımlanmış fonksiyonlar meşru kabul edilir ve yukarıda gösterilen yapı tipini dayamayacak kadar sıklıkla kullanılırlar. Eğer durum buysa, ayrıntılı olmayan modellerin neden yararlı/meşru olduğunu açıklayabilir misiniz?

cevap

33

Desen eşlemesinin kapsamlı olmadığını düşünmeniz gereken durumlar vardır. (Negatif sayılar herhangi davayı eşleşmiyor)

fac 0 = 1 
fac n | n > 0 = n * fac (n-1) 

bu kapsamlı olmayan olduğu sonucunu verir: Bu optimum uygulanmasını olmayabilir Örneğin, ben bunu derlemek olmasaydı yardımı olacağını sanmıyorum Faktoriyel fonksiyonun tipik kullanımı için gerçekten önemli değildir. İşte

mod2 :: Integer -> Integer 
mod2 n | even n = 0 
mod2 n | odd n = 1 

tüm vakalar ele alınacak, ancak derleyici muhtemelen bunu tespit edemez:

Ayrıca genellikle bir desen maçı ayrıntılı ise derleyici için karar vermek mümkün olmayabilir. Gardiyanlar keyfi olarak karmaşık olabileceğinden, derleyici desenlerin kapsamlı olup olmadığına her zaman karar veremez. Tabii ki bu örnek otherwise ile daha iyi yazılabilir, ama aynı zamanda mevcut haliyle derlemesi gerektiğini düşünüyorum.

+4

Başka bir yaygın durum, bir bekçi/davanın/şubenin içinde lambda ifadeleri olacaktır. Argümanın içinde bulunduğunuz branştan dolayı belirli bir formu olduğunu biliyorsunuz, bu yüzden lambda dahil olmak gereksizdir. –

+1

Aksi halde yazılması gerektiğini düşünmüyorum. Derleyici, non-exahustive olduğunu düşünüyor olsa bile, harika bir mod2 tanımıdır. Bu soruya geldim çünkü negatif tamsayılar için tanımlanmaması gereken bir fib fonksiyonu yazarken bu hatayı aldım. –

+0

belki bu kapsam dışıdır, ancak bir desen eşleşmesinin zorlayıcı olup olmadığını veya durma problemiyle ilişkili olmadığına karar veriyor? sezgisel olarak, bu tür analizleri en azından dilin alt kümeleri için kullanması gerektiği gibi kesin bir şekilde yazılmış bir dil gibi görünüyor, ama bağırsak içgüdülerinin genellikle bir şeyin hesaplanabilir olup olmadığını tahmin etmenin korkunç bir yolu olduğunu biliyorum. – kai

12

Uyarıları hatalara dönüştürmek için -Werror kullanabilirsiniz. Kusursuz olmayan desen uyarılarını hatalara dönüştürebilir miyim bilmiyorum, üzgünüm! Sorunuzun üçüncü kısmına gelince

:

Bazen birlikte yakın çalışma ve kolayca Haskell ifade edemez özelliklere sahip olma eğilimi fonksiyonları bir dizi yazın. Bu işlevlerden en azından bazıları, genellikle 'tüketiciler' olmak üzere kapsamlı olmayan modellere sahip olma eğilimindedir. Bu, örneğin, birbirinin 'sıralaması' olan işlevlerde ortaya çıkar.

Bir oyuncak örneği: Şimdi (eleman tipi Eq olmadığı zamanlarda) removeDuplicates (duplicate as)as eşit olduğunu görmek oldukça kolaydır, ama bir tek sayı olduğundan genelde duplicate (removeDuplicates bs), kilitlenmesine

duplicate :: [a] -> [a] 
duplicate [] = [] 
duplicate (x:xs) = x : x : xs 

removeDuplicates :: Eq a => [a] -> [a] 
removeDuplicates [] = [] 
removeDuplicates (x:y:xs) | x == y = x : removeDuplicates xs 

elemanlar veya 2 ardışık eleman farklıdır. Çarpmazsa, ilk etapta bsduplicate tarafından üretilmiştir (ya da üretilmiştir).Yani

aşağıdaki kanunlar (geçerli değil Haskell) var: Buraya kapsamlı olmayan desenleri önlemek istiyorsanız Şimdi

removeDuplicates . duplicate == id 
duplicate . removeDuplicates == id (for values in the range of duplicate) 

, sen removeDuplicates dönüş Maybe [a] yapmak veya eksik hata iletileri ekleyebilirsiniz vakalar. Sen

newtype DuplicatedList a = DuplicatedList [a] 

duplicate :: [a] -> DuplicatedList a 
removeDuplicates :: Eq a => DuplicatedList a -> [a] 
-- implementations omitted 

çizgisinde bir şey yapmak bile tek şey kolayca (Haskell tipi sisteminde 'unsurlar eşit olma ardışık çiftiyle, hatta uzunlukta bir liste olma' ifade edemez, çünkü bu, gereklidir Eğer Oleg değilseniz

Ancak, removeDuplicates dışa aktarmazsanız, burada kapsamlı olmayan desenleri kullanmanın mükemmel olduğunu düşünüyorum. İhracat yaptığınız anda, girdiler üzerinde kontrolü kaybedersiniz ve kayıp vakalarla uğraşmak zorunda kalacaksınız!

+0

Sanırım kaldırmayı kastetmişsinizdir (x: y: xs) | x == y = x: removeDosyaları xs. – gawi

+0

Teşekkürler, tamir ettim! – yatima2975

İlgili konular