【问题标题】:Writing in pointfree style f x = g x x以无点风格写作 f x = g x x
【发布时间】:2012-02-06 23:45:26
【问题描述】:

我正在学习 Haskell。很抱歉问了一个非常基本的问题,但我似乎找不到答案。我有一个由 f 定义的函数:

f x = g x x

其中 g 是已定义的 2 个参数的函数。我如何编写这种无点风格? 编辑:不使用 lambda 表达式。

谢谢

【问题讨论】:

    标签: haskell pointfree


    【解决方案1】:

    f可以写成Control.Monad.join

    f = join g
    

    函数 monad 上的join 是构造无点表达式时使用的原语之一,因为它本身不能以无点样式定义(其SKI calculus 等效,SII — @ Haskell 中的 987654330@ - 不输入).

    【讨论】:

    • 我想你的意思是f = join g
    • @user1188374,join 函数是 monad 的基本函数,在这种情况下,monad 是函数 monad,(->) r 是一些 rjoin :: Monad m => m (m a) -> m a的定义;用(->) r 代替m 得到join :: (r -> r -> a) -> (r -> a)
    • @user1188374: join 是无点风格的原语,因为 SII 到 Haskell 的翻译 ap id id 是无效的——它有一个类型错误(具体来说,它失败occurs check)。它在 SKI 组合子演算中有效,因为它是无类型的。
    • join 等于 flip ap id,因此可以说它不是原始的。请注意,虽然某些 SKI 表达式不键入,但它们通常不是唯一的,有时替代方案会更好。例如,I = SKK = SKS,但在这两个中只有 ap const const 具有您想要的类型。
    • @misterbee 它在Control.Monad.Instances 中声明。
    【解决方案2】:

    这被称为"W" combinator

    import Control.Monad
    import Control.Monad.Instances
    import Control.Applicative
    
    f = join g       -- = Wg        (also, join = (id =<<))
      = (g `ap` id)  -- \x -> g x (id x) = SgI
      = (<*> id) g   --                  = CSIg
      = g =<< id     -- \x -> g (id x) x
      = id =<< g     -- \x -> id (g x) x
    

    S,K,I 是一组基本的组合子; B,C,K,W 是另一个 - 你必须在某处 (回复:你的“无 lambda 表达式”评论)

    _B = (.)     -- _B f g x = f (g x)     = S(KS)K
    _C = flip    -- _C f x y = f y x       = S(S(K(S(KS)K))S)(KK)
    _K = const   -- _K x y   = x
    _W = join    -- _W f x   = f x x       = CSI = SS(KI) = SS(SK)
    _S = ap      -- _S f g x = f x (g x)   = B(B(BW)C)(BB) = B(BW)(BBC)
       = (<*>)                                -- from Control.Applicative
    _I = id      -- _I x     = x           = WK = SKK = SKS = SK(...)
    
    {-
    Wgx = gxx 
        = SgIx = CSIgx 
               = Sg(KIg)x = SS(KI)gx
        = gx(Kx(gx)) = gx(SKgx) = Sg(SKg)x = SS(SK)gx
    
    -- _W (,) 5 = (5,5)
    -- _S _I _I x = x x = _omega x         -- self-application, untypeable
    -}
    

    【讨论】:

    • 停止点是一个组合子。一个例子是 ι (iota) 组合器 - λf.fSKSKI 然后表示为 S = ι(ι(ι(ιι)))K = ι(ι(ιι))I = ιι。这个基础对于简单类型的 λ 演算不是那么友好,ιι 甚至不进行类型检查。 U = λf.fKSK 好一点(不知道有没有名字,所以我就叫它U 通用); S = U(UU)K = UUU
    • @Vitus yes, yes。我想这更像是一个方便的问题,在哪里停止,在一个实用的设置中。例如,在 Haskell 中,我们有 SKI BCKW 组合子很方便。
    • ... 还有,f = g =&lt;&lt; id = id =&lt;&lt; g
    【解决方案3】:

    我来到这里纯属偶然,我想提供我的解决方案,因为在这个帖子中还没有人提到提升,至少没有明确地提到。

    这是一个解决方案:

    f = liftM2 g id id
    

    怎么看?

    • g 具有 a -&gt; a -&gt; b 类型,即它需要 某种类型的两个值(两者的类型相同,否则 OP 给出的 f 的定义不会有意义),并返回另一个 某种类型的值(不一定与参数的类型相同);

    • lift2M gg 的提升版本,它的类型为(Monad m) =&gt; m a -&gt; m a -&gt; m b:它采用两个一元值,每个值都是迄今为止未指定的值上下文,并返回一个一元值

    • 当将两个函数传递给liftM2 g 时,将在Monad 的上下文中投掷骰子:值尚未存在,但最终会存在,当函数将接收它需要的参数;换句话说,函数是存储自己未来值的单子;因此,lift2M g 接受两个函数的输入(或者,两个函数的未来值),并返回另一个函数(或者,它的未来值);知道了这个,把m改成(-&gt;) r,或者r -&gt;:(r -&gt; a) -&gt; (r -&gt; a) -&gt; (r -&gt; b)

    • 我们传递的两个函数都是id,它保证它会返回它收到的相同值;

    • 因此liftM2 g id id 是一个r -&gt; b 类型的函数,它将其参数传递给这两个ids,使其保持不变并将其转发给g

    以类似的方式,可以利用函数是应用函子,并使用以下解决方案:

    f = g <$> id <*> id
    

    【讨论】:

    • liftA2,对于函数(即Reader monad)与liftM2相同:liftA2 k f g x = k (f x) (g x)。 (这个就在:liftA2 (,) === (&amp;&amp;&amp;) :))。
    • 嗨@WillNess,你的每一条评论都会在我的学习列表中添加一个空复选框,哈哈哈。这种语言只是让我想回到大学。好吧,我什至不知道在意大利哪里可以学习:/。我想我必须搜索一下。
    • 搜索 Eugenio Moggi,作为初学者。 :)(顺便说一句,g &lt;$&gt; x &lt;*&gt; y === liftA2 g x y,或多或少定义为 IIRC)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多