【问题标题】:Is there a way to make h (f x) (g x) point-free in Haskell?有没有办法在 Haskell 中使 h (f x) (g x) 无点?
【发布时间】:2013-11-22 20:01:59
【问题描述】:

我想我想要 J 的 fork 功能。有没有办法做到这一点?

【问题讨论】:

  • 通过询问pointfree 程序:pointfree "m h f g x = h (f x) (g x)" -> m = liftM2。 @kqr 的答案是等效的,并且可能会更好,因为 Applicative 实例通常比 Monad 实例更有效。
  • @bheklilr 难道pointfree 建议liftM* 它是在liftA* 存在之前编写的吗?只要 applicative 是 monad 的超类,我们就可以将 liftM2 扔出窗外,不是吗?
  • @kqr 我想是这样,或者可能只是pointfreeControl.Applicative 之前查找Control.Monad。是否可能存在 liftA*liftM* 具有不同实现的 Monad?我的猜测是行为将是相同的,但由于 Applicatives 有时可以在 Monads 不能添加并行性的地方添加并行性,所以我暂时不会将 liftM* 扔出窗外。
  • @bheklilr 这取决于它们是否“允许”不同。 Monoid e => Either e 承认一个整洁的 Applicative 不能形成一个 Monad,但是一旦 Applicative-Monad 提案命中,它会变得更加奇怪,因为实例不同......

标签: haskell fork pointfree


【解决方案1】:

这是,使用所谓的应用风格,

h <$> f <*> g

使用来自Control.Applicative&lt;$&gt;&lt;*&gt;


另一种方法是将h 提升到(-&gt;) r applicative functor with

liftA2 h f g

这背后的直觉是如果

h        ::    a     ->    b     ->   c
-- then --
liftA2 h :: (r -> a) -> (r -> b) -> r -> c

所以提升版本采用两个函数r -&gt; something 而不是实际的somethings,然后提供一个r 以从函数中获取somethings。


liftA*&lt;$&gt;&lt;*&gt; 的对应组合是等价的。

【讨论】:

    【解决方案2】:

    虽然@kqr 有基于Applicative 实例的((-&gt;) a) 更实用的解决方案,但我们也可以在“pipey”方法中讨论它

            +----- f ------+
           /                \
    <---- h                  +------< x
           \                /
            +----- g ------+
    

    它提供了一种非常组合的无点程序。我们将使用来自Control.Arrow 的工具来创建这个程序。

    首先,我们使用 Haskell 中常见的缺失函数 diagdup 获得图表的最右边部分

    --+
       \
        +----- x        dup :: x -> (x, x)
       /                dup x = (x, x)
    --+
    

    然后使用来自Control.Arrow(***) 组合子创建中​​间

    ----- f -----     (***)   :: (a -> b) -> (c -> d) -> (a, c) -> (b, d)
                      f       :: (a -> b)
                      g       ::             (c -> d)
    ----- g -----     f *** g ::                         (a, c) -> (b, d)
    

    那么左边就是uncurry为我们做的事情

      +--    uncurry   :: (a -> b -> c) -> (a, b) -> c
     /       h         :: (a -> b -> c)
    h        uncurry h ::                  (a, b) -> c
     \   
      +--
    

    然后将它们连接在一起,我们可以以非常组合的方式擦除x 点。

    m :: (a -> b -> c) -> (x -> a) -> (x -> b) -> x -> c
    m h f g = uncurry h . (f *** g) . dup
    
                      +------ f ----+
                     /               \
             <----- h                 +-----------< x (eta reduced)
                     \               /
                      +------ g ----+
    

    【讨论】:

    • 这是一种非常巧妙的思考问题的方式。出于好奇:它是如何扩展到相当于 liftA3 f g1 g2 g3 的?
    • 不太好。您必须做更多的工作来打包和解包嵌套对。我将介绍标准的Control.Arrow 组合器f &amp;&amp;&amp; g = (f *** g) . dup,然后我们有liftA3 f g1 g2 g3 = uncurry ($) . first (uncurry f) . first (g1 &amp;&amp;&amp; g2) . second g3 . dup。布莱赫。
    • 对于交叉引用,我经常听到这种编程叫做“对演算”中的编程。
    • @J.Abrahamson 出于好奇,有没有类似 Arrow 的库可以优雅地处理 liftA3 案例?
    • 哇,我把liftM3 版本弄错了一点。它并没有我想象的那么糟糕:liftM3 f g1 g2 g3 = uncurry ($) . (uncurry f . (g1 &amp;&amp;&amp; g2)) &amp;&amp;&amp; g3。我们甚至可以在Arrow (-&gt;) 实例中使用apply :: uncurry ($) 来编写apply . ((uncurry f . (g1 &amp;&amp;&amp; g2)) &amp;&amp;&amp; g3) 甚至apply . (liftA2 f g1 g2 &amp;&amp;&amp; g3),这提供了一个很好的递归关系,让我们生成[liftAn | n &lt;- [1..]]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-19
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多