【问题标题】:haskell, chaining filtershaskell,链接过滤器
【发布时间】:2009-11-10 23:38:09
【问题描述】:

将“map f (map g xs)”写成一个单独的 map 调用,你可以写

示例 xs = 地图 (f.g) xs

但是你如何将“filter p (filter q xs)”写成一个单独的过滤调用呢?点运算符似乎不适用于过滤器,因为它适用于地图。猜你会用别的东西做谓词吗?

【问题讨论】:

    标签: haskell filter


    【解决方案1】:

    如果您定义了如下所示的函数both

    both :: (a -> Bool) -> (a -> Bool) -> a -> Bool
    both f g x = f x && g x
    

    那么你可以写:

    example xs = filter (both p q) xs
    

    我不确定是否有一个标准函数可以为您执行此操作...

    【讨论】:

    • 谢谢伙计,这确实有效。仍然认为可能有更直接的方法来做到这一点(?)
    【解决方案2】:
    $ ghci 前奏> :m +Control.Arrow Prelude Control.Arrow> :t uncurry (&&) 。 ((0 a -> Bool Prelude Control.Arrow> filter (uncurry (&&) . ((0

    如果您经常这样做,也可以声明自己的运算符。

    infixr 3 &&:
    p &&: q = \a -> p a && q a
    infixr 2 ||:
    p ||: q = \a -> p a || q a
    not' = (.) not
    all' = foldr (&&:) $ const True
    any' = foldr (||:) $ const False
    
    example xs = filter (p &&: q ||: not' r) xs
    

    【讨论】:

      【解决方案3】:

      为什么不是列表推导式?

      example = [x | x <- xs, p x, q x]
      -- for example
      example = [x | x <- [1..10], (>3) x, x<5 ] -- [4]
      

      【讨论】:

      • 是的,列表理解在这里很好用。这个问题实际上源于我本周的一个教程,这意味着有一种简单的方法可以做到这一点。列表理解是迄今为止我发现的最快的,我开始认为可能没有像 map 和“函数组合”那样的比较方式。谢谢大家!
      • 您可以随时制定重写规则。转换过滤器 f 。将 g 过滤到 \a -> 过滤器 (f a && g a)。当然,这只是更优雅的列表推导的替代品,尽管这可能更快(预感)。
      【解决方案4】:

      在某物上调用函数列表本质上是 Control.Monad 中的 ap 函数所做的。然后你只需and 结果。唯一有点难看的是ap 要求它的两个参数都在同一个monad 中(在本例中为List),所以我们需要将它与return 组合起来才能在这里工作。

      import Control.Monad
      filterByMany funcs = filter (and . ap funcs . return)
      

      【讨论】:

        【解决方案5】:

        我会定义一个 lambda 表达式。

        module Main where
        
        overTen :: Int -> Bool
        overTen = (>10)
        
        main :: IO ()
        main = do
            print $ filter (\x -> overTen x && even x) [1..20]
        

        输出:

        $ ghci Test.hs
        GHCi, version 6.10.4: http://www.haskell.org/ghc/  :? for help
        Loading package ghc-prim ... linking ... done.
        Loading package integer ... linking ... done.
        Loading package base ... linking ... done.
        [1 of 1] Compiling Main             ( Test.hs, interpreted )
        Ok, modules loaded: Main.
        *Main> main
        [12,14,16,18,20]
        *Main>
        

        【讨论】:

        • 这就是GHC -O2 自动执行的操作(几乎:涉及重写规则的几个不同阶段,并且通常中间阶段在之前/而不是被转回过滤器之前与其他内容相结合)
        【解决方案6】:
        import Data.Foldable
        import Data.Monoid
        
        p = (>4)
        g = (<10)
        
        main = print $ filter (getAll . foldMap (All.) [p,g]) [1..10]
        

        输出

        [5,6,7,8,9]
        

        仅仅因为列表是可折叠的,并且您可以将谓词结果与All monoid 结合起来

        【讨论】:

          【解决方案7】:

          类似的东西呢:

          example xs = filter (forAll [p,q,r,s,t,u,v]) xs
          
          forAll:: [(a -> Bool)] -> a -> Bool
          forAll funcs x = all (map ($ x) funcs)
          

          【讨论】:

          • 你的意思是,forAll fs x = and [f x | f &lt;- fs]。 :) 使用allforAll fs x = all ($ x) fs(没有map)。 :)
          【解决方案8】:

          我会定义一个辅助函数——这可能会以更声明的方式编写,但我没有在这个系统上安装 GHCI 进行测试:

          allPredicates :: [a -> Bool] -> a -> Bool
          allPredicates []     _ = True
          allPredicates (p:ps) x = p x && allPredicates ps x
          

          然后

          filter (allPredicates [p, q]) xs
          

          【讨论】:

          • allPredicates = (. flip ($)) . flip all
          • 或者稍微不那么模糊的allPredicates x y = all (flip ($) y) x。 GHC 解决flip 的复杂用法的效率如何?出于性能目的,我之前似乎需要删除 flip 的用法。哦,John 的allPredicates 可能性能很差,因为不能内联递归函数。哦奇怪,Data.Listall 的定义中没有where go ...,我很确定你需要内联。
          • 啊,不,“静态参数转换”使其非递归:stackoverflow.com/a/9660027/667457
          猜你喜欢
          • 2017-02-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-22
          • 1970-01-01
          • 1970-01-01
          • 2011-02-03
          • 1970-01-01
          相关资源
          最近更新 更多