[英]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)
x
和y
在那一點上的類型無關緊要。
由於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)
它是一個返回元組的函數。 如果你想把它變成一個函數元組,你可以用fst
和snd
組成它:
(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
類型的值,並在元組中返回它們的結果(類型c
和d
)。 所以在這里你可以這樣做:
split = (fst .) &&& (snd .)
(q, r) = split (12345 `quotRem`)
然而,如果你看一下(length . filter even, length . filter odd)
,它已經是一個元組,
(Integral a, Integral b) => ([a] -> Int, [b] -> Int)
這就是為什么你當然可以解構這個元組來綁定evens
和odds
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.