7

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

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?任何人都可以帮助我更好地理解这个组合背后的逻辑吗?

4

3 回答 3

15

如果你当时开始删除一个论点,你会得到

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

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

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

于 2012-09-13T15:22:04.923 回答
13

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

f . g  $ x
f .: g $ x y
于 2012-09-13T19:45:32.713 回答
3

显式使用curryanduncurry可以帮助在“多参数”和单参数函数之间切换。

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

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

于 2021-06-04T17:52:43.810 回答