Haskell提供了很多其他語言不具備的靈活性。這樣做的代價是有很多情況下,其他語言會給你一個語法或類型錯誤,但Haskell不會。讓我們把你的例子:
3 4 :: (Num (a -> t), Num a) => t
在Haskell,如果您有任何兩個語法有效的表達,使他們彼此相鄰,其間還爲您提供了一個有效的表達空白。因此,例如,如果f
和x
兩種表達,這也是一個表達式:
f x
這種類型的表達的被稱爲功能應用,或簡稱只是應用。
除此語法規則外,還有一個輸入規則。我會寫上前面的表達式類型註釋:
((f :: a -> b) (x :: a)) :: b
也就是說,對於應用程序得到很好的類型的,那麼對於類型a
和b
,f :: a -> b
,x :: a
和f x :: b
一些選擇。
它使用什麼類型推斷你的程序的語法結構和任何顯式類型的註釋,您和您使用已經提供給弄清楚,可以分配給你的表達最普遍的類型庫。
所以現在,回到你的例子:
3 4 :: (Num (a -> t), Num a) => t
這種表達是語法上有效的應用,因爲它具有f x
形式我上面所解釋的。此外,整數常量3
和3
都有一段a
(爲一個字面的每次出現獨立地選自)類型Num a => a
。把所有這些東西放在一起,好吧,我們有一個句法結構良好的表達式,如果單獨採用,也會進行類型檢查。
你可能認爲這是瘋狂的,在某些情況下,一個整數文字可能是一個功能......但好,沒有這麼多。一個例子是:我曾經在那裏我使用的Haskell到原型數據轉換和查詢,其中在DSL表達式靜置功能從輸入幀(查詢條件)到值的域專用語言的項目。舉例來說,一個框架可能是一組對年/月值及營業員的,和值可能是由銷售人員在該月的售電量,或單位出售數量:
sales :: (YearMonth, Salesperson) -> Money
units :: (YearMonth, Salesperson) -> Integer
有的straightfoward方式(其中icktoofay的回答證明)的擴展Num
類,讓我們寫這樣的表述:
avgSales :: (YearMonth, Salesperson) -> Money
avgSales = sales/fromIntegral units
,並延長Num
類這樣也可以讓我們像對待3
整數文字作爲文字DSL。對應於3
功能爲常數函數返回3
無論(YearMonth, Salesperson)
組合是什麼:
salesTimesThree :: (YearMonth, Salesperson) -> Money
salesTimesThree = sales * 3
在實踐中你不能延伸到Num
功能類型,然而,您可以定義爲這個新的類型(以及增加對查詢做IO來從文件或數據庫中的數據的能力):
newtype Query tag point value =
Query { runQuery :: Set (Tagged tag point) -> IO (Map (Tagged tag point) value) }
instance Functor (Query tag point) where ....
instance Applicative (Query tag point) where ....
instance Num value => Num (Query tag point value) where ....
但仍然是利落有作任何類型的成數的能力在那裏你可以明智地提供Num
操作。隱含的缺點是你所說的:錯誤信息將不那麼有用。
事實上,'3 4'不編譯!如果沒有,你會看到一個類型錯誤,而不是一個類型。實際上並沒有關係,因爲'3 4'編譯的原因是類型類是開放的,所以有人可能會出現並定義一個實例'Num(a - > a)'在這個點上'3 4 '有價值。 – user2407038 2014-11-02 04:43:10
我不知道這是否是重複本身,而是看到[這個問題和它的答案(http://stackoverflow.com/q/26515102/1186208)。謝謝你(含蓄地)同意我說'(3 4)'是一種可憎的東西 - 但是,如果你寫這個實例,它就會遵循並且毫無怨言地運行。 (相當於3.) – 2014-11-02 04:46:07