关于Haskell中的currying和point自由风格的困惑

时间:2009-05-25 16:24:24

标签: haskell currying pointfree

我试图实现这个功能

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

这是this question的主题。我尝试这样做没有明确的递归。我想出了以下代码

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

我的功能不起作用,因为它不是懒惰的(这在问题中是必需的),因此没有赞成: - )。

然而,我并没有就此止步。我尝试使函数无点,以便它更短(甚至可能更酷)。由于参数fxs是表达式中的最后一个,我只是将它们删除了:

every = liftM (all id) $ sequence $ map 

但是这没有按预期工作,事实上它根本不起作用:

    [1 of 1] Compiling Main             ( stk.hs, interpreted )

    stk.hs:53:42:
        Couldn't match expected type `[m a]'
               against inferred type `(a1 -> b) -> [a1] -> [b]'
        In the second argument of `($)', namely `map'
        In the second argument of `($)', namely `sequence $ map'
        In the expression: liftM (all id) $ sequence $ map
    Failed, modules loaded: none.

为什么?我的印象是,可以简单地删除尾随函数参数,这基本上就是currying的内容。

1 个答案:

答案 0 :(得分: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

应用程序运算符$的一个模式是它经常成为合成运算符。在免费版本中。这是因为

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