我试图实现这个功能
every :: (a -> IO Bool) -> [a] -> IO Bool
这是this question的主题。我尝试这样做没有明确的递归。我想出了以下代码
every f xs = liftM (all id) $ sequence $ map f xs
我的功能不起作用,因为它不是懒惰的(这在问题中是必需的),因此没有赞成: - )。
然而,我并没有就此止步。我尝试使函数无点,以便它更短(甚至可能更酷)。由于参数f
和xs
是表达式中的最后一个,我只是将它们删除了:
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的内容。
答案 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