【问题标题】:"Mapping" scanl“映射”扫描
【发布时间】:2012-08-30 19:47:19
【问题描述】:

给定一个列表:: [(Foo, Bar)],我想对Bars 执行scanl1,但保留他们的Foo“标签”。

即我想要一个类型为:: [(a, b)] -> ([b] -> [c]) -> [(a, c)] 的函数,这样我就可以传递一个咖喱scanl1 作为第二个参数。

我可以递归地编写它,但感觉好像有一种方法可以组合高阶函数来做到这一点。

这已经可以用标准函数实现了吗?

【问题讨论】:

    标签: haskell higher-order-functions


    【解决方案1】:

    您可以提升组合函数以将 Foo 标记穿过,这样您仍然可以使用 scanl1 ,而不是编写令人不满意的高阶函数,这就是您的意思。

    keeptags :: (Bar -> Bar -> Bar) -> (Foo,Bar) -> (Foo,Bar) -> (Foo,Bar)
    keeptags g (_,b) (a',b') = (a',g b b')
    

    现在你可以使用scanl1;带上你原来的qux :: Bar -> Bar -> Bar 并制作

    scanQux :: [(Foo,Bar)] -> [(Foo,Bar)]
    scanQux = scanl1 (keeptags qux) 
    

    keeptags 很简单,scanQux 非常清晰。

    例如,如果

    type Foo = Char
    type Bar = Int
    
    qux = (+)
    

    然后你得到

    *Main> scanl1 qux [1..9]
    [1,3,6,10,15,21,28,36,45]
    
    *Main> zip "HELLO MUM" [1..9]
    [('H',1),('E',2),('L',3),('L',4),('O',5),(' ',6),('M',7),('U',8),('M',9)]
    
    *Main> scanQux $ zip "HELLO MUM" [1..9]
    [('H',1),('E',3),('L',6),('L',10),('O',15),(' ',21),('M',28),('U',36),('M',45)]
    

    如你所愿。

    【讨论】:

      【解决方案2】:

      你是说unzip

      http://zvon.org/other/haskell/Outputprelude/unzip_f.html

      x = zip a c
        where
          (a, b) = unzip my_list
          c = what_ever_you_want_on b
      

      【讨论】:

      • 这让我知道((uncurry zip) . (\(a,b) -> (a, scanl1 f b)) . unzip),但感觉还是有更简单的方法......
      • @amindfv: 用import Control.Arrow,你可以写uncurry zip . second (scanl1 f) . unzipsecond 将函数应用于元组的后半部分。 Control.Arrow 中的类型很复杂,但如果您只是将 Arrow a => a b c 视为 b -> c,则该模块包含一组出色的组合器,用于编写无点函数和/或处理元组。
      • @AntalS-Z:很高兴知道。我认为它应该作为一个答案。
      【解决方案3】:

      我的朋友为keeptags 带来了以下实现:

      import Control.Arrow
      
      keeptags g (_,b) = second (g b)
      

      我认为它仍然可读。

      【讨论】:

      • 这很棒 - 干净简单!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-05
      相关资源
      最近更新 更多