2011-12-15 22 views
12

新哈斯克爾很抱歉,如果這是很基本的從函數的類型確定功能行爲

這個例子是從「真實世界哈斯克爾」拍攝 -

ghci> :type fst 
fst :: (a, b) -> a 

他們展示的類型fst功能,然後按照它與本款...

「的fst結果類型爲a。我們已經提到,參數多態使得將R EAL類型不可訪問:fst沒有足夠的信息來構造a類型的值,也不能把一個ab。因此,唯一可能的有效行爲(省略無限循環或崩潰)可以返回該對中的第一個元素。「

我覺得我錯過了該段的基本觀點,並且可能是Haskell的一些重要內容爲什麼不能在fst函數返回類型b?爲什麼不可以把元組作爲PARAM,但只返回Int(或任何其他類型的不a)?我不明白爲什麼它必須返回類型a

謝謝

回答

24

如果它做了任何這些事情,它的類型會改變。這句話所說的是,鑑於我們知道fst(a, b) -> a類型,我們可以對它進行扣除。如果它有不同的類型,我們將無法這樣做。

例如,看到

snd :: (a, b) -> a 
snd (x, y) = y 

不類型檢查,所以我們知道(a, b) -> a類型的值不能表現得像snd

參數性基本上是這樣一個事實,即某種類型的多態函數必須遵守某些規律構造 - 即沒有不符合它們的類型的良好類型表達式。所以,爲了能夠用它來證明fst的事情,我們必須首先知道fst的類型。

請注意特別是多態性那裏:我們不能對非多態類型做同樣的推導。例如,

myFst :: (Int, String) -> Int 
myFst (a, b) = a 

型檢查,但這樣做

myFst :: (Int, String) -> Int 
myFst (a, b) = 42 

甚至

myFst :: (Int, String) -> Int 
myFst (a, b) = length b 

Parametricity關鍵依賴於一個事實,一個多態函數不能 「看」它被調用的類型。因此fst知道的類型的一個的唯一值就是它給出的那個值:元組的第一個元素。

2

這裏的要點是ab都是類型變量(可能是相同的,但不需要)。無論如何,因爲對於給定的兩個元素的元組,fst總是返回第一個元素,返回的類型必須始終與第一個元素的類型相同。

5

問題是,一旦你有了這種類型,實現選項就會受到很大限制。如果您返回Int,那麼您的類型將是(a,b) -> Int。由於a可能是任何東西,我們不能憑藉undefined而在實施過程中無精打采,因此必須返回由調用者給予我們的一個。

4

您應該閱讀Theorems for Free文章。

+11

在完成RWH的第2章之前? – ehird 2011-12-15 18:52:42

+1

這是一篇免費的文章,hahaha – 2011-12-16 01:09:26

+1

@他希望得到一個深入的解釋,所以在這裏。其他人已經給出了基本的揮手解釋 – nponeccop 2011-12-16 09:44:27

3

讓我們嘗試添加一些更多的手揮手已經由真實世界哈斯克爾給出的。讓我們試着說服自己,因爲我們有型(a,b) -> a唯一的總功能也可以是一個功能fst是以下之一:

fst (x,y) = x 

首先,我們不能返回任何其他然後a類型的值,那是因爲fst的類型爲(a,b) -> a,所以我們不能有fst (x,y) = yfst (x,y) = 1,因爲它沒有正確的類型。

現在,RWH說,如果我給fst(Int,Int)fst不知道這些都是整型,此外,ab不屬於任何類型的類,以便fst有關聯沒有可用的值或功能所需ab

所以fst只知道在a值和b價值,我給它,我不能把ba(它不能使一個b -> a功能),所以它必須返回給定a值。

這實際上並不是真正的魔法揮手,而是實際上可以推斷出給定多態類型有哪些可能的表達式。實際上有一個名爲djinn的程序就是這麼做的。

2

你可能缺少基本的事情是這樣的:

  • 在大多數編程語言,如果你說「這個函數返回任意類型」,這意味着功能可以決定什麼類型的它實際返回的值。

  • 在Haskell中,如果你說「此函數返回任何類型」,這意味着調用者可以決定應該是什麼類型。 (!)

所以,如果我你寫foo :: Int -> x,它不能只返回一個String,因爲我可能不會問它的String。我可能會要求CustomerThreadId任何東西

顯然,foo無法知道如何創建每種可能類型的值,即使是尚不存在的類型。總之,不可能寫foo。你嘗試的所有東西都會給你類型錯誤,並且不會編譯。

(警告:有做一個方式foo可能永遠循環下去,或者拋出一個異常,但它不能返回一個有效的值。)

有沒有辦法讓一個函數是能夠創建任何可能類型的值。但它完全可能的函數來移動數據而不關心它是什麼類型。因此,如果你看到一個接受任何類型數據的函數,它可以做的唯一事情就是移動它。

或者,如果類型必須屬於某個特定的類,那麼函數可以使用該類的方法。 (莫非,它沒有,但它可以如果就是了。)

從根本上說,這就是爲什麼你其實可以告訴什麼功能只要看一眼它的類型簽名確實。類型簽名告訴你函數「知道」它將要提供的數據,以及它可能執行什麼操作。這就是爲什麼通過類型簽名來搜索Haskell函數非常有用的原因。

你聽說過「在Haskell中,如果它編譯通常是正確的」?那麼,這是爲什麼。 ;-)

相關問題