2017-05-07 58 views
0

我正在做一個Haskell類型的練習,這個難題讓我難堪。所提供的表達式爲:瞭解這個表達式的Haskell類型

f2 f g h = h.g.f 

而對於f2的類型是顯然:

f2 :: (a -> b1) -> (b1 -> b) -> (b -> c) -> a -> c 

這似乎對於這樣的短表達過於複雜。有人可以解釋爲什麼這種類型有意義嗎?

回答

3

你爲什麼覺得這很複雜?它只是一個接受三個函數(匹配類型)並返回一個新函數的函數。

我已將b1更名爲b並更新了其他名稱以保持一致性。因此,這裏是一個稍微修改版本:

f2 :: (a -> b) -> (b -> c) -> (c -> d) -> a -> d

  • 這裏,f2需要f其類型a -> b。意思是說,它是一個函數,用一些類型的輸入aa可以是任何東西,這裏沒有限制)和一些返回值類型b
  • 然後f2需要g哪個輸入的類型必須匹配f的輸出,所以它是b -> c。它不可能像e -> c(其中eb不同),或者代碼無效,因爲它不可能組成f . g
  • 對於第三個參數hc -> d類型完全相同。
  • 函數組成的結果(f2返回的結果)是一個新函數,它接受任何f並返回任何h返回值,因此它是a -> d。有了這個,我們已經涵蓋了整個類型定義。

基本上,這是一個相對較長的定義,但我認爲它是一個非常簡單的本質。

+0

第四點是什麼讓我困惑,我理解到那裏。具體而言,我不會得到「接受任何回報,並返回任何回報」, –

+0

好吧,我盯着它看了一會兒,我現在明白了爲什麼我給出的例子中的d或c會在那裏,但我是仍然有些困惑,爲什麼必須在那裏。 –

+1

@KaiD:考慮一個稍微簡單的例子'f3 f g = f。 g',其類型爲'f3 ::(a - > b) - >(b - > c) - > a - > c'。它有兩個函數('f'和'g'),併產生一個新函數。在'a - > c'部分,它表示生成的函數的輸入類型將是'a' - 與'f'相同的類型。返回類型是'd',與'g '回報。例如,如果'f'接受一個字符串並返回一個整數,'g'接受一個整數並返回一個布爾值,那麼'f3'的結果必須接受一個字符串並返回一個布爾值 - 這就是類型聲明所說的。說得通? – drdaeman

3

我發現這些「確定這樣和那樣的表達的類型」通常有點倒退。類型應該總是優先:你想爲某個任務編寫一個解決方案,你將問題描述作爲一個類型簽名。 然後你繼續前進,實際編寫一個實現。

在這種情況下,你的問題開始:我有三個功能fgh,和類型的值,我可以傳遞給f。此外,函數具有成對匹配的結果/參數類型。因此,簽名

f2 :: (α -> β) -> (β -> γ) -> (γ -> δ) -> α -> δ 

現在你可以去和明確的尖形式實現這一點,即

f2 f g h x = h (g (f x)) 

這仍然是相當短暫的。畢竟,這是一項非常簡單的任務!

但是在Haskell中,通過使用標準組合運算符.可以使它更短。最終實施非常短的事實基本上是由於f2.基本相同,只是兩次。所以這並不比使用複雜類型簽名的非常複雜的任務更令人驚訝,但是發現一些包含幾乎完成任務的函數的庫。很顯然,調用這個ready-build函數會比任務複雜度提供的實現要短得多,但複雜性只能推遲到庫函數。

+0

我和你在同一個問題上等同於(b - > c),但我不明白爲什麼類型表達式不僅僅在那裏結束。爲什麼我需要接下來的兩個,就我而言 - > a - > c? –

+1

@KaiD因爲類型表達式覆蓋了返回值。 'a - > c'('α - >δ')是'f2'返回的一種類型。 – drdaeman