【发布时间】:2016-08-09 11:46:53
【问题描述】:
对于函数f :: a → b、g :: c → d,我该如何编写lambda
\(x, y) → (f x, g y) :: (a, b) → (c, d)
更简洁?我尝试了(f, g),但是——正如我猜想的那样——没有成功。
【问题讨论】:
对于函数f :: a → b、g :: c → d,我该如何编写lambda
\(x, y) → (f x, g y) :: (a, b) → (c, d)
更简洁?我尝试了(f, g),但是——正如我猜想的那样——没有成功。
【问题讨论】:
(,) 的 Bifunctor 实例是您正在寻找的:
instance Bifunctor (,) where
bimap f g (a, b) = (f a, g b)
bimap 将两个函数应用于一个元组,一个应用于每个元素。
> import Data.Bifunctor
> bimap (+1) (*5) (1,1)
(2, 5)
您可能想知道bimap 和(***) 之间的区别是什么。
> :t bimap
bimap :: Bifunctor p => (a -> b) -> (c -> d) -> p a c -> p b d
> :t (***)
(***) :: Arrow a => a b c -> a b' c' -> a (b, b') (c, c')
使用bimap,您可以将类型限制为元组而不是任意双函子p,这样使用p ~ (,),bimap 的类型就变成了
(a -> b) -> (c -> d) -> (a, c) -> (b, d).
使用(***),您可以将类型限制为函数而不是任意箭头a,这样使用a ~ (->),(***) 的类型就变成了
(b -> c) -> (b' -> c') -> (b, b') -> (c, c')
仔细观察会发现这两种受限类型是等价的。
【讨论】:
Bifunctor 实例。其实是bimap f g ~(x, y) = (f x, g y),这只是“道德上正确的”,一不小心可能会导致空间泄漏。
~。
您可以从Control.Arrow 使用(***),即
f *** g
【讨论】:
试试
import Control.Arrow
answer = f *** g $ (a, c)
例如
import Control.Arrow
f :: Int -> Int
f = (+1)
g :: Double -> String
g = show
answer = f *** g $ (10, 3.5)
【讨论】: