【问题标题】:Short way to write (\(x, y) -> (f x, g y))简写方式 (\(x, y) -> (f x, g y))
【发布时间】:2016-08-09 11:46:53
【问题描述】:

对于函数f :: a → bg :: c → d,我该如何编写lambda

\(x, y) → (f x, g y) :: (a, b) → (c, d)

更简洁?我尝试了(f, g),但是——正如我猜想的那样——没有成功。

【问题讨论】:

    标签: haskell tuples


    【解决方案1】:

    (,)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),这只是“道德上正确的”,一不小心可能会导致空间泄漏。
    • 哎呀,我以为我从here复制了它,但显然不是。我的眼睛一定已经忽略了~
    【解决方案2】:

    您可以从Control.Arrow 使用(***),即

    f *** g
    

    【讨论】:

      【解决方案3】:

      试试

      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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-25
        • 1970-01-01
        相关资源
        最近更新 更多