【问题标题】:Pointfree Composition with Multiple Variables具有多个变量的无点组合
【发布时间】:2012-09-13 15:18:20
【问题描述】:

我已经开始关注它,并且更喜欢将它用于简单的情况,在这种情况下,我基本上可以将值从一个输出传递到一个输入。我喜欢的无点组合的一个简单示例是:

let joinLines = foldr (++) "" . intersperse "\n"

今天在玩 GHCI 时,我想看看我是否可以编写 not(==) 来复制 (/=),但我真的无法推理出来。 (==) 接受两个输入,not 接受一个。我认为这可能有效:

let ne = not . (==)

假设(==) 的单个Bool 输出将转到not,但它不会编译,引用以下错误:

<interactive>:1:16:
    Couldn't match expected type `Bool' with actual type `a0 -> Bool'
    Expected type: a0 -> Bool
      Actual type: a0 -> a0 -> Bool
    In the second argument of `(.)', namely `(==)'
    In the expression: not . (==)

我希望我能说这对我来说意义重大,但我得到的只是传递给(==) 的第二个参数可能是在为not 搞砸?谁能帮我更好地理解这个组合背后的逻辑?

【问题讨论】:

  • 对于无积分的爱好者:您正在寻找的组合器是(.).(.) :: (b -&gt; c) -&gt; (a -&gt; a1 -&gt; b) -&gt; a -&gt; a1 -&gt; c,或fmap . fmap
  • @phipsgabler,当“第一个”函数采用 3 个参数(如 (.).(.).(.))时,这会起作用吗?
  • @Alexey Phew。抱歉,我是 8 年前写的,已经有几年没有使用 Haskell 了 :) 用 :t 在 GHCI 中试试吧,我猜?
  • @phipsgabler,我想会的,我希望你能确认一下,这样我就不用多想了:)。

标签: haskell function-composition pointfree


【解决方案1】:

如果你当时开始删除一个参数,你会得到

ne x y = not (x == y)
       = (not . (x ==)) y
ne x   = not . (x ==)
       = not . ((==) x)
       = ((not .) . (==)) x
ne     = (not .) . (==)

基本上,对于每个参数,您都需要一个 (.),并正确关联。

(==) 的类型是Eq a =&gt; a -&gt; a -&gt; Bool。因此,如果您编写whatever . (==),并将值x 传递给它,您将得到whatever ((==) x),但(==) x 是一个函数a -&gt; Bool(其中ax 的类型,以及一个实例Eq)。所以whatever 必须接受函数类型的参数。

【讨论】:

  • 逻辑上这对我来说是有意义的,它可以编译,但会导致(例如)ne 1 1 上的运行时错误:“没有由文字 1' Possible fix: add an instance declaration for (Num ()) In the second argument of 引起的 (Num ()) 实例ne',即1' In the expression: ne 1 1 In an equation for it': it = ne 1 1"
  • 这就是单态性限制。给绑定一个类型签名,或者禁用 MR (:set -XNoMonomorphismRestriction)。对于ghci,后者更容易,对于文件,我推荐前者。
  • 好吧,对我来说是全新的。谢谢。我相信这将有助于我为未来的事情做好准备。编辑:刚刚在 ghci 中尝试了后者,它确实有效。当它允许我时,我会将你标记为答案:p
  • 更详细地说,let ne = (not .) . (==) 使用简单的模式绑定 [无函数参数] 且没有类型签名来绑定 ne。通过 MR,受此类绑定绑定的实体必须具有单态类型。因此,推断类型ne :: Eq a =&gt; a -&gt; a -&gt; Bool 中的类型变量必须专门用于具体类型。 ghci 的扩展默认规则将其专门用于()。在文件中,该约束不可默认 [除非您启用 ExtendedDefaultRules] 并导致编译错误。
【解决方案2】:

另一个有用的运算符是 (.:),它是带有两个参数的初始函数的组合子:

f . g  $ x
f .: g $ x y

【讨论】:

  • +1 提供信息。显然只是为此创建了一个帐户:p
  • 这是在某处标准定义的吗?我通常称它为oo(在 ML 中)并将其定义为:oo = (.) . (.),但我不知道它是否在 Base 的某个地方。
  • @singpolyma,不错的缩写。然后ooo = (.).(.).(.)(用于将3个参数的函数与一个参数的函数组合在一起)等等......
【解决方案3】:

明确使用curryuncurry 有助于在“多参数”和单参数函数之间切换。

ne = curry (not . uncurry (==))

uncurry“修复”(==),使其采用单个参数(x,y),而不是单独的xy 参数。然后可以按预期使用not 组合生成的函数。组合函数,然后可以重新柯里化以再次接受单独的参数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-03
    • 2019-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-28
    • 2012-08-19
    • 1970-01-01
    相关资源
    最近更新 更多