1

在函數子類的定義,我們的<$函數定義爲:

class Functor f where 
    fmap  :: (a -> b) -> f a -> f b 

    (<$)  :: a -> f b -> f a 
    (<$)  = fmap . const 

const函數的定義:

const     :: a -> b -> a 
const x _    = x 

我知道<$功能等同於:

\x -> fmap (const x) 

fmap . const如何等於上面的lambda表達式?我對函數組合的理解是輸出類型const應該與輸入類型fmap匹配,但輸入類型fmap是函數(a -> b)而不是a這是const函數輸出的內容。

+0

你的問題啓發了我檢查Data.Map的'<$'的定義。在下一個版本中它會更快。謝謝! – dfeuer

回答

4

對方回答不解決這個問題,「如何fmap . const等同於lambda表達式之上?」一個良好的工作,所以我想,以解決不同的部分:

我的函數組合的理解是const的輸出類型應與fmap的輸入類型匹配,但fmap的輸入類型是功能(a -> b)而不是a,這是const函數輸出的內容。

在這個答案,我會認爲的const輸出類型確實需要通過fmap的功能。

讓我們重寫類型的fmapconst,使用單獨的類型變量中的每個避免混淆:

fmap :: Functor f => (a -> b) -> (f a -> f b) 
const :: c -> (d -> c) 

現在,人們不禁要問:是什麼const輸出類型?在你的問題中,你假定輸出類型是c(在如上修正類型變量重命名之後)。但實際上這是一個輕微的誤解;真正的輸出類型是d -> c

const的輸出實際上是一個函數。現在,如您所說,其輸出必須與fmap的輸入相匹配。通過我們上面的命名,這意味着我們必須選擇滿足等式d ~ a(閱讀:類型d和類型a是相同類型)並滿足c ~ b。那麼我們將有:

const  :: b -> (a -> b) 
fmap   ::  (a -> b) -> (f a -> f b) 
fmap . const :: b    -> (f a -> f b) 
+0

這是我正在尋找的答案。所以我上面的評論說,部分應用的函數被映射到仿函數是不正確的。它實際上是正在應用的(d - > c)的函數。 –

5

需要注意的是:

(f . g) x = f (g x) 

(見definition of (.)),因此,

(fmap . const) x = fmap (const x) 

原來的答案

爲具體,讓我們使用IO仿函數。

fmap f通過將f應用於計算結果來處理IO計算。

E.g. - getContentsIO String,並length是字符串的函數,所以我們可以在getContents FMAP長度:

getContents    :: IO String 
length     :: String -> Int 
fmap length getContents ::    IO Int 

在運行時,這將讀取所有標準輸入,走輸入的長度,並將其返回(作爲IO行動)。

現在,const z是忽略其參數並始終返回z的函數。所以,如果我fmap (const 'w')getContents我會:

getContents     :: IO String 
const 'w'      :: String -> Char 
fmap (const 'w') getContents ::    IO Char 

在執行時,這將首先在所有標準輸入讀取,則丟棄輸入,並返回「W」字。

+0

是的,我知道這一點。但是我想知道的是這個構圖如何等於lambda表達式。 –

+0

答覆已更新。 – ErikR

+0

所以實際上,'const x'是一個部分應用的函數,它在這種情況下將'fmap'ed給傳遞給它的任何函子。 –

相關問題