【问题标题】:Transforming a function in Haskell to point free notation将 Haskell 中的函数转换为无点表示法
【发布时间】:2018-11-04 18:11:59
【问题描述】:

我以纸上的haskell函数为例:

function2 a b c = (a * b) + c 

我需要用无点符号来编写示例。我真的不擅长使用无点样式,因为我发现它真的很混乱,没有适当的指导,所以我试了一下:

function2 a b c = (a * b) + c
function2 a b c = ((*) a b) + c #operator sectioning
function2 a b c = (+) ((*) a b)c #operator sectioning once more
#I'm stuck here now

我不确定接下来应该出现什么,因为这是我能想到的这个例子的限制。希望能得到一些帮助。

--第二个例子:

function3 a b = a `div` (g b)
function3 a b = `div` a (g b) --operator sectioning
function3 a b = (`div` a) (g b) --parentheses
function3 a b = ((`div` a g).)b --B combinator
function3 a   = ((`div` a g).) --eta conversion
function3 a   = ((.)(`div` a g)) --operator sectioning
function3 a   = ((.)flip(`div` g a))
function3 a   = ((.)flip(`div` g).a) --B combinator
function3     = ((.)flip(`div` g)) --eta conversion (complete)

【问题讨论】:

    标签: haskell pointfree


    【解决方案1】:

    您可以在此处应用 B 组合符(即(f . g) x = f (g x)):

    function2 a b c = (a * b) + c
    function2 a b c = ((*) a b) + c    -- operator sectioning
    function2 a b c = (+) ((*) a b) c  -- operator sectioning once more
          = (+) (((*) a) b) c          -- explicit parentheses
          = ((+) . ((*) a)) b c        -- B combinator
          = ((.) (+) ((*) a)) b c      -- operator sectioning 
          = ((.) (+) . (*)) a b c      -- B combinator
    

    确实类型是一样的:

    > :t let function2 a b c = (a * b) + c in function2
    let function2 a b c = (a * b) + c in function2
      :: Num a => a -> a -> a -> a
    
    > :t ((.) (+) . (*))
    ((.) (+) . (*)) :: Num b => b -> b -> b -> b
    

    我们以正确的顺序一一提取参数,最终得到

    function2 a b c = (......) a b c
    

    以便 eta-contraction 可以用来摆脱显式参数,

    function2       = (......) 
    

    我们的工具,我们可以在两个方向应用,是

    S a b c  =  (a c) (b c)  =  (a <*> b) c
    K a b    =  a            =  const a b
    I a      =  a            =  id a
    B a b c  =  a (b c)      =  (a . b) c
    C a b c  =  a c b        =  flip a b c
    W a b    =  a b b        =  join a b
    U a      =  a a          -- not in Haskell: `join id` has no type
    

    还有(f =&lt;&lt; g) x = f (g x) x = join (f . g) x

    当我们使用 pointfree 一段时间后,会出现一些其他有用的模式:

    ((f .) .) g x y = f (g x y)
    (((f .) .) .) g x y z = f (g x y z)
    .....
    ((. g) . f) x y = f x (g y)
    ((. g) . f . h) x y = f (h x) (g y)
    

    (更新。)在您的第二个示例中,开始附近有一个错误,使其之后的所有以下步骤无效:

    function3 a b = a `div` (g b)
    function3 a b = -- `div` a (g b)     -- wrong syntax, you meant
                    div a (g b)
    function3 a b = -- (`div` a) (g b)   -- wrong; it is
                    (a `div`) (g b) --operator sectioning
    function3 a b = ((a `div`) . g) b --B combinator
    function3 a   = (div a . g) --eta conversion; back with plain syntax
    function3 a   = (.) (div a) g --operator sectioning
    function3 a   = flip (.) g (div a) --definition of flip
    function3 a   = (flip (.) g . div) a --B combinator
    function3     = (flip (.) g . div) --eta conversion
                  = (.) (flip (.) g) div  --operator section
    

    是的,有些步骤是朝着正确的方向。

    【讨论】:

    • 对不起,我不明白。 ((.) (+) ((*) a)) b c = ((.) (+) . (*)) a b c 怎么样?如果这被视为(f . g) x = f (g x),那么这里的fg 是什么?
    • @TobiMcNamobi f = (.) (+) = ((.) (+)) ; g = (*) ; (f (g a)) == (f . g) ab, c 只是挂起,与 this 转换无关。多余的括号也无关紧要。
    • @WillNess 感谢您之前的详尽解释。因此,基于此,我在上面更新的帖子中尝试了另一个示例,如果您能评估它并告诉我我是否符合规则,将不胜感激。
    • @WillNess 谢谢。一个问题,为什么它的 div a (g b) 然后又恢复为 (a div) (g b)? ` ` 是否在变化中起作用?
    • 一开始是没有必要的。
    【解决方案2】:

    我们可以继续:

    function2 a b = (+) ((*) a b)     [eta-reduction]
    function2 a = (+) . (*) a         [using a dot, to eliminate the b]
    function2 = ((.) . (.)) (+) (*)   ["blackbird" operator to pass two parameters]
    

    这里的"blackbird operator" 是三个(.) :: (b -&gt; c) -&gt; (a -&gt; b) -&gt; a -&gt; c 运算符的组合。它在功能上等同于:

    ((.) . (.)) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
    ((.) . (.)) f g x y = f (g x y)
    

    在此处查看derivation

    【讨论】:

    • 我想你称它为“猫头鹰”是为了避免人们在实践中将其称为另一种猫头鹰,但在 combinator birds 的常见鸟舍中,猫头鹰 O 是λfg.g(fg);这是黑鸟 B₁ = λfgxy.f(gxy),有时拼写为 (.:)(...)fmap fmap fmap,如果你想傻的话。不过,对于我的无点代码,我更喜欢只添加一个 fmapfmap (+) . (*),因为即使它只是这里的组合,在语义上我认为它是“映射”额外的参数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    • 2013-12-23
    • 2019-08-02
    • 1970-01-01
    • 2021-06-06
    • 1970-01-01
    相关资源
    最近更新 更多