【问题标题】:Is eta reduction possible?eta减少可能吗?
【发布时间】:2014-05-07 13:07:10
【问题描述】:

是否可以在以下情况下应用 eta 减少?

let normalise = filter (\x -> Data.Char.isLetter x || Data.Char.isSpace x )

我期待这样的事情是可能的:

let normalise = filter (Data.Char.isLetter || Data.Char.isSpace)

...但事实并非如此

【问题讨论】:

    标签: haskell pointfree


    【解决方案1】:

    您的解决方案不起作用,因为(||) 适用于Bool 值,而Data.Char.isLetterData.Char.isSpace 的类型为Char -> Bool

    pl 给你:

    $ pl "f x = a x || b x"
    f = liftM2 (||) a b
    

    解释:liftM2(||) 提升为(->) r monad,所以它的新类型是(r -> Bool) -> (r -> Bool) -> (r -> Bool)

    所以在你的情况下,我们会得到:

    import Control.Monad
    let normalise = filter (liftM2 (||) Data.Char.isLetter Data.Char.isSpace)
    

    【讨论】:

    • 对此(stolen from @JAbrahamson)的一个很好的补充是定义(<||>) = liftM2 (||),然后您可以将其用作filter (isLetter <||> isSpace),甚至可以像filter (isLetter <||> isSpace <||> (== '1'))一样继续组合它们。我发现这种风格特别容易使用和吸引人。
    【解决方案2】:
    import Control.Applicative
    let normalise = filter ((||) <$> Data.Char.isLetter <*> Data.Char.isSpace)
    

    【讨论】:

      【解决方案3】:

      另一个值得研究的解决方案涉及箭头!

      import Control.Arrow
      
      normalize = filter $ uncurry (||) . (isLetter &&& isSpace)
      

      &amp;&amp;&amp; 采用两个函数(实际上是箭头)并将它们的结果压缩到一个元组中。然后我们只是取消||,所以是时候变成(Bool, Bool) -&gt; Bool了,我们都完成了!

      【讨论】:

        【解决方案4】:

        您可以利用Any monoid 和返回 monoid 值的函数的 monoid 实例:

        import Data.Monoid
        import Data.Char
        
        let normalise = filter (getAny . ((Any . isLetter) `mappend` (Any . isSpace)))
        

        【讨论】:

          猜你喜欢
          • 2018-04-13
          • 1970-01-01
          • 1970-01-01
          • 2011-04-04
          • 1970-01-01
          • 1970-01-01
          • 2013-07-06
          • 1970-01-01
          • 2020-11-01
          相关资源
          最近更新 更多