簡體   English   中英

有沒有辦法在Haskell中捕獲高階函數的元組?

[英]Is there a way to capture a tuple of higher-order functions in Haskell?

我知道在Haskell中模式匹配函數是不可能的 ,我完全理解為什么。 但是,我有兩個密切相關的問題。 首先,如果您想部分應用函數以供以后使用,是否有一種方法可以定義和捕獲返回值(如果它是一個元組)? 或者我錯了,這還在嘗試模仿我鼻子下的匹配功能?

例如,假設我正在嘗試獲取具有10的不同倍數的值的商和余數。 然后,我怎么寫這樣的東西?

q, r :: Integral a => a -> a
(q, r) = (12345 `quotRem`)

我在這里意識到,存在單獨的功能,所以我可以這樣做:

q, r :: Integral a => a -> a
q = (12345 `quot`)
r = (12345 `rem`)

但是,這是一個非常具體的案例,並且有無限的其他函數示例返回元組,這些函數很容易推廣。 例如,一個返回列表中的平均數和賠率的函數。

evens, odds :: Integral a => [a] -> Int
(evens, odds) = (length . (filter even), length . (filter odd))

這引出了我的第二個問題。 以上在GHCi中工作得很好。

Prelude> let (evens, odds) = (length . (filter even), length . (filter odd))
Prelude> :t evens
evens :: Integral a => [a] -> Int
Prelude> evens [1..10]
5

更令人困惑的是,它甚至可以通過“模式匹配”工作,就像我在開始時使用(q, r)

Prelude> let evensOdds = (length . (filter even), length . (filter odd))
Prelude> :t evensOdds
evensOdds :: (Integral a1, Integral a) => ([a1] -> Int, [a] -> Int)
Prelude> let (ev,od) = evensOdds
Prelude> :t ev
ev :: Integral a1 => [a1] -> Int
Prelude> ev [1..10]
5

它也可以在加載到GHCi中的實際文件中正常工作,即使(evens, odds)也沒有。 為什么這兩個不同,為什么第二個在GHCi中工作,如果它不能正常工作? 可以通過某種方式利用這里的不同之處嗎?

你永遠不會在一個函數上模式匹配。 您始終在pair-constructor (,)上進行模式匹配。 你的(even, odds)例子

(evens, odds) = (length . (filter even), length . (filter odd))

就像工作一樣

(first, second) = (x, y)

xy在那一點上的類型無關緊要。


由於quotRem的類型(q, r)你的(q, r)示例不起作用。 讓我們回顧它並將其與(q, r)的類型進行比較:

quotRem       :: Integral n => n -> n -> (n     , n)
quotRem 12345 :: Integral n =>      n -> (n     , n)
(q, r)        :: Integral n =>           (n -> n, n -> n)

如您所見,對(q, r) '類型與quotRem的類型不同。 仍然可以編寫你的函數:

pairify :: (a -> (b, c)) -> (a -> b, a -> c)
pairify f = (fst . f, snd . f)

(q,r) = pairify (quotRem 12345)

但正如你所看到的,我們不會從pairify獲得太多pairify 順便說一句, Data.List partition提供了你的(even, odds)功能:

(even, odds) = pairify (partition even)

看看(12345 `quotRem`)的類型:

Integral a => a -> (a, a)

它是一個返回元組的函數。 如果你想把它變成一個函數元組,你可以用fstsnd組成它:

(q, r) = (fst . f, snd . f)
  where f = (12345 `quotRem`)

如果你想以無點的方式做到這一點,一種方法是使用Control.Arrow&&&組合器。 它的完全一般類型是:

Arrow a => a b c -> a b d -> a b (c, d)

專門針對->箭頭,那是:

(b -> c) -> (b -> d) -> b -> (c, d)

因此它需要兩個函數,每個函數都取b類型的值,並在元組中返回它們的結果(類型cd )。 所以在這里你可以這樣做:

split = (fst .) &&& (snd .)
(q, r) = split (12345 `quotRem`)

然而,如果你看一下(length . filter even, length . filter odd) ,它已經是一個元組,

(Integral a, Integral b) => ([a] -> Int, [b] -> Int)

這就是為什么你當然可以解構這個元組來綁定evensodds

暫無
暫無

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

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