Haskell中柯里化和无参函数风格的混淆问题

10

我试图实现这个函数

every :: (a -> IO Bool) -> [a] -> IO Bool 

这是这个问题的主题。我尝试在没有显式递归的情况下完成此操作,我得出了以下代码:

every f xs = liftM (all id) $ sequence $ map f xs

我的函数没有工作,因为它不是惰性的(这在问题中是必需的),所以没有点赞 :-)。

然而,我并没有止步于此。我试图使函数成为无参数的,这样它会更短(也许更酷)。由于参数fxs是表达式中的最后一个,所以我只需删除它们:

every = liftM (all id) $ sequence $ map 

但是这并没有像预期的那样工作,实际上根本不起作用:

    [1 of 1] Compiling Main             (stk.hs,解释)
stk.hs:53:42:         无法匹配预期类型“ [ma]”                对抗推断类型`(a1-> b) - > [a1] -> [b]'         在“ $”的第二个参数中,也就是“映射”的第二个参数中         在表达式中:“ liftM(all id)$ sequence $ map”     失败,模块已加载:none。

为什么会这样?我原本以为可以简单地删除尾随函数参数,这基本上就是柯里化的内容。

1个回答

25

$ 的定义是:

f $ x = f x

让我们完全加上括号来表示你的函数:

every f xs = (liftM (all id)) (sequence ((map f) xs))

以及您的柯里化版本:

every = (liftM (all id)) (sequence map)

正如您所注意到的那样,它们并不完全相同。只有在末尾应用时才能省略最后一个函数参数。例如:

f x = g c x

实际上是

f x = (g c) x

并且将(g c)应用到x的操作放在最后,因此您可以写成:

f = g c

在it技术中,应用运算符$的一种常见模式是它在无点版本中通常变成了组合运算符.。这是因为

f $ g $ x

等同于

(f . g) $ x

例如,
every f xs = liftM (all id) $ sequence $ map f xs

可以成为

every f xs = (liftM (all id) . sequence . map f) xs

在这个时候,您可以删除 xs:

every f = liftM (all id) . sequence . map f

消除参数f是更加困难的,因为它应用于组合运算符之前。让我们使用来自http://www.haskell.org/haskellwiki/Pointfree的点定义:

dot = ((.) . (.))

使用“积分”来解释,这就是它的含义:

(f `dot` g) x = f . g x

这正是我们需要的,让每个点满足无点语法:

every = (liftM (all id) . sequence) `dot` map

遗憾的是,由于Haskell类型系统的限制,这个函数需要一个显式的类型签名:

every :: (Monad m) => (a -> m Bool) -> [a] -> m Bool

2
或者你可以使用-XNoMonomorphismRestriction并且省略显式类型签名。 - GS - Apologise to Monica
1
啊...这个“点”定义看起来像有人盯着我。 - gawi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接