2017-10-11 80 views
6

Preludenull函數的定義如下:爲什麼Haskell Prelude中的null函數的定義很奇怪?

null    :: [a] -> Bool 
null []   = True 
null (_:_)  = False 

什麼讓我感到困惑的是定義的第三行,爲什麼不把它寫:

null(_:_)  = False 

相反的:

null any = False 

它與編譯器優化有什麼關係?

+1

沒有。沒關係。這個定義非常清楚地表明,沒有錯過任何東西,但對於那些實際上並不重要的列表。 – dfeuer

+1

另外,你可以定義'null = all(const False)'。也許這會更清楚。 – dfeuer

回答

5

它與編譯器優化有什麼關係?

非也,其實可以說,寫null (_:_)null any效率更低(如果編譯器不優化了這一點),因爲現在你問哈斯克爾驗證它確實是一個「缺點」。雖然如果編譯器在數據類型上做了一些簿記,那麼優化它當然很容易。據我所知,大多數編譯器如ghc和差不多所有不是由三歲孩子編寫的編譯器確實會這樣做。所有的

首先,它是更好的寫wilcard _(或命名any),因爲列表的定義(以及任何其他數據類型可能會改變)。雖然列表的可能性不大,但有人可能會重新定義一個列表。例如,如:

data [a] = [] | (a:[a]) | (Int///[a]) 

其中例如後一種模式意味着該列表重複多次。在那種情況下,一個不是由三歲小孩編寫的編譯器:)將警告大約對於null不完整的模式:它將因此聲稱(_///_)模式未被指定。而如果您使用通配符,它​​將回退到null any的情況。

一般來說,最好小心使用通配符:只有當你真的不關心給函數賦予什麼時,你應該使用通配符。

+4

它*效率不高。編譯器*總是*優化這個。 – dfeuer

+2

@dfeuer:這是一個奇怪的說法,因爲沒有提到具體的編譯器。有朝一日,我可以編寫一個Haskell編譯器,但不這樣做。我的說法並不是一個好的編譯器不會優化這個。這個想法只是在語法上,前者效率較低。 :) –

+0

沒有「語法上效率較低」這樣的事情。具有代數數據類型的靜態類型語言的體面編譯器始終在這方面做得很好。請記住,編譯器必須檢查每個構造函數是否具有正確的類型;雖然它在,它可以很容易地檢查所有的存在。這對於GADT來說要複雜得多,但這些在這裏並不相關。 – dfeuer