簡體   English   中英

什么(f。)。在Haskell中意味着什么?

[英]What does (f .) . g mean in Haskell?

我已經看到很多函數是根據模式定義的(f .) . g (f .) . g 例如:

countWhere = (length .) . filter
duplicate  = (concat .) . replicate
concatMap  = (concat .) . map

這是什么意思?

點運算符(即(.) )是函數組合運算符。 它的定義如下:

infixr 9 .
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)

正如您所看到的,它需要類型為b -> c函數和類型為a -> b另一個函數,並返回類型為a -> c的函數(即將第一個函數應用於第二個函數的結果)。

函數組合運算符非常有用。 它允許您將一個函數的輸出傳遞給另一個函數的輸入。 例如,你可以在Haskell中編寫一個tac程序,如下所示:

main = interact (\x -> unlines (reverse (lines x)))

不太可讀。 但是使用函數組合,您可以按如下方式編寫它:

main = interact (unlines . reverse . lines)

正如您所看到的,功能組合非常有用,但您無法在任何地方使用它。 例如,您無法使用函數組合將filter的輸出filterlength

countWhere = length . filter -- this is not allowed

不允許這樣做的原因是因為filter的類型是(a -> Bool) -> [a] -> [a] 將它與a -> b進行比較,我們發現a的類型為(a -> Bool)b的類型為[a] -> [a] 這導致類型不匹配,因為Haskell期望lengthb -> c類型(即([a] -> [a]) -> c )。 然而它實際上是[a] -> Int

解決方案非常簡單:

countWhere f = length . filter f

然而,有些人不喜歡那個額外的懸掛f 他們更喜歡以countWhere 樣式編寫countWhere ,如下所示:

countWhere = (length .) . filter

他們怎么得到這個? 考慮:

countWhere f xs = length (filter f xs)

-- But `f x y` is `(f x) y`. Hence:

countWhere f xs = length ((filter f) xs)

-- But `\x -> f (g x)` is `f . g`. Hence:

countWhere f = length . (filter f)

-- But `f . g` is `(f .) g`. Hence:

countWhere f = (length .) (filter f)

-- But `\x -> f (g x)` is `f . g`. Hence:

countWhere = (length .) . filter

如你所見(f .) . g (f .) . g只是\\xy -> f (gxy) 這個概念實際上可以迭代:

f . g             --> \x -> f (g x)
(f .) . g         --> \x y -> f (g x y)
((f .) .) . g     --> \x y z -> f (g x y z)
(((f .) .) .) . g --> \w x y z -> f (g w x y z)

它並不漂亮,但它完成了工作。 給定兩個函數,您還可以編寫自己的函數組合運算符:

f .: g = (f .) . g
f .:: g = ((f .) .) . g
f .::: g = (((f .) .) .) . g

使用(.:)運算符,您可以編寫countWhere ,如下所示:

countWhere = length .: filter

有趣的是,你也可以用點自由風格編寫(.:)

f .: g = (f .) . g

-- But `f . g` is `(.) f g`. Hence:

f .: g = (.) (f .) g

-- But `\x -> f x` is `f`. Hence:

(f .:) = (.) (f .)

-- But `(f .)` is `((.) f)`. Hence:

(f .:) = (.) ((.) f)

-- But `\x -> f (g x)` is `f . g`. Hence:

(.:) = (.) . (.)

同樣我們得到:

(.::)  = (.) . (.) . (.)
(.:::) = (.) . (.) . (.) . (.)

正如你所看到的那樣(.:)(.::)(.:::)只是(.)冪(即它們是(.) 迭代函數 )。 對於數學中的數字:

x ^ 0 = 1
x ^ n = x * x ^ (n - 1)

類似於數學中的函數:

f .^ 0 = id
f .^ n = f . (f .^ (n - 1))

如果f(.)那么:

(.) .^ 1 = (.)
(.) .^ 2 = (.:)
(.) .^ 3 = (.::)
(.) .^ 4 = (.:::)

這使我們接近本文的結尾。 對於最后的挑戰,讓我們以無點樣式編寫以下函數:

mf a b c = filter a (map b c)

mf a b c = filter a ((map b) c)

mf a b = filter a . (map b)

mf a b = (filter a .) (map b)

mf a = (filter a .) . map

mf a = (. map) (filter a .)

mf a = (. map) ((filter a) .)

mf a = (. map) ((.) (filter a))

mf a = ((. map) . (.)) (filter a)

mf = ((. map) . (.)) . filter

mf = (. map) . (.) . filter

我們可以進一步簡化如下:

compose f g = (. f) . (.) . g

compose f g = ((. f) . (.)) . g

compose f g = (.) ((. f) . (.)) g

compose f = (.) ((. f) . (.))

compose f = (.) ((. (.)) (. f))

compose f = ((.) . (. (.))) (. f)

compose f = ((.) . (. (.))) (flip (.) f)

compose f = ((.) . (. (.))) ((flip (.)) f)

compose = ((.) . (. (.))) . (flip (.))

使用compose您現在可以將mf寫為:

mf = compose map filter

是的它有點難看,但它也是一個令人難以置信的令人難以置信的概念。 你現在可以編寫形式\\xyz -> fx (gyz)任何函數作為compose fg ,這非常簡潔。

這是一個品味問題,但我發現這種風格令人不愉快。 首先,我將描述它的意義,然后我建議我更喜歡的替代方案。

你需要知道(f . g) x = f (gx)(f ?) x = f ? x (f ?) x = f ? x對於任何運營商? 由此我們可以推斷出這一點

countWhere p = ((length .) . filter) p
              = (length .) (filter p)
              = length . filter p

所以

countWhere p xs = length (filter p xs)

我更喜歡使用一個名為.:的函數.:

(.:) :: (r -> z) -> (a -> b -> r) -> a -> b -> z
(f .: g) x y = f (g x y)

然后countWhere = length .: filter 就個人而言,我發現這一點更加清晰。

.:Data.Composition定義,也可能在其他地方定義。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM