有没有办法在 Haskell 中捕获高阶函数的元组?
Is there a way to capture a tuple of higher-order functions in Haskell?
我理解 Haskell 中的 ,我完全理解为什么。但是,我有两个密切相关的问题。首先,如果您想部分应用函数供以后使用,是否有一种方法可以定义和捕获 return(如果它是一个元组)?还是我错了,这还在我眼皮子底下尝试模式匹配功能?
例如,假设我正在尝试获取一个值的各种十的倍数的商和余数。那我怎么写这样的东西呢?
q, r :: Integral a => a -> a
(q, r) = (12345 `quotRem`)
我意识到这里存在单独的函数,所以我可以这样做:
q, r :: Integral a => a -> a
q = (12345 `quot`)
r = (12345 `rem`)
但是,这是一个非常特殊的情况,return 元组的函数还有无数其他示例可以很好地概括。例如,returns 列表中偶数和奇数的函数。
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
更令人困惑的是,"pattern-matching" 的工作方式与我一开始玩 (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 中完全可以工作?可以以某种方式利用这里的不同之处吗?
您永远不会在函数上进行模式匹配。您总是在对构造函数 (,)
上进行模式匹配。您的 (even, odds)
示例
(evens, odds) = (length . (filter even), length . (filter odd))
就像
一样工作
(first, second) = (x, y)
此时 x
和 y
的类型无关紧要。
由于 quotRem
的类型,您的 (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
中获得太多收益。顺便说一句,Data.List
中的 partition
提供了您的 (even, odds)
功能:
(even, odds) = pairify (partition even)
看(12345 `quotRem`)
的类型:
Integral a => a -> (a, a)
returns一个元组是一个函数。如果你想把它做成一个函数元组,你可以用 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
类型的值,并且 returns 它们的结果(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
.
我理解 Haskell 中的
例如,假设我正在尝试获取一个值的各种十的倍数的商和余数。那我怎么写这样的东西呢?
q, r :: Integral a => a -> a
(q, r) = (12345 `quotRem`)
我意识到这里存在单独的函数,所以我可以这样做:
q, r :: Integral a => a -> a
q = (12345 `quot`)
r = (12345 `rem`)
但是,这是一个非常特殊的情况,return 元组的函数还有无数其他示例可以很好地概括。例如,returns 列表中偶数和奇数的函数。
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
更令人困惑的是,"pattern-matching" 的工作方式与我一开始玩 (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 中完全可以工作?可以以某种方式利用这里的不同之处吗?
您永远不会在函数上进行模式匹配。您总是在对构造函数 (,)
上进行模式匹配。您的 (even, odds)
示例
(evens, odds) = (length . (filter even), length . (filter odd))
就像
一样工作(first, second) = (x, y)
此时 x
和 y
的类型无关紧要。
由于 quotRem
的类型,您的 (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
中获得太多收益。顺便说一句,Data.List
中的 partition
提供了您的 (even, odds)
功能:
(even, odds) = pairify (partition even)
看(12345 `quotRem`)
的类型:
Integral a => a -> (a, a)
returns一个元组是一个函数。如果你想把它做成一个函数元组,你可以用 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
类型的值,并且 returns 它们的结果(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
.