在Haskell中关于currying和点自由风格的混淆 [英] Confusion about currying and point free style in Haskell
问题描述
我试图实现这个功能:
every ::(a - > IO Bool) - > [a] - > IO Bool
这是这个问题。我试图在没有显式递归的情况下执行 。我想出了以下代码:
每个f xs = liftM(全部id)$ sequence $ map f xs
我的功能不起作用,因为它不是懒惰的(这在问题中是必需的),所以没有upvotes那里: - )。
然而,我并没有停留在那里。我试图使无点功能,以便它更短(甚至更酷)。由于参数 f
和 xs
是表达式中最后一个,所以我放弃了它们:
every = liftM(all id)$ sequence $ map
但是这并没有像预期的那样工作,事实上它根本不起作用:
[1 1]编译主(stk.hs,解释)
stk.hs:53:42:
无法匹配预期的类型`[ma]'
与推断的类型'$($)'的第二个参数,即'map'
在'($)'的第二个参数中, ',即`sequence $ map'
在表达式中:liftM(all id)$ sequence $ map
失败,模块加载:无。
这是为什么?我的印象是可以简单地删除拖尾函数参数,这基本上就是currying的含义。
$的定义是
$ b让我们将函数完全加括号:
每个f xs =(liftM(all id))(sequence((map f)xs))
和您的咖喱版本:
every =( liftM(all id))(sequence map)
正如您注意到的,这些不一样。当它们是最后一个应用的时候,你只能删除尾随函数参数。例如,
fx = gcx
其实是
fx =(gc)x
,并且(gc)到x的应用最后一次,因此您可以写入
f = gc
应用程序操作符$的一种模式是它经常成为组合运算符。在免费版本中。这是因为
f $ g $ x
相当于
(f。g)$ x
例如,
every f xs = liftM(all id)$ sequence $ map f xs
可以变成
每个f xs =(liftM(全部id)。sequence。map f)xs
此时您可以放弃xs:
每f = liftM(全部id)。序列 。 map f
消除参数f更加困难,因为它在合成运算符之前应用。让我们使用 http://www.haskell.org/haskellwiki/Pointfree 中的点定义:
dot =((。)。(。))
$ p
$ b有点数,这是
(f`dot` g) x = f。 gx
并且正是我们需要让每一个完全无点的东西:
every =(liftM(all id)。sequence)`dot` map
不幸的是,由于Haskell类型系统的限制,这个需要一个明确的类型签名:
every ::(Monad m)=> (a - > m Bool) - > [a] - > m Bool
I was trying to implement the function
every :: (a -> IO Bool) -> [a] -> IO Bool
which was the topic for this question. I tried to do this without explicit recursion. I came up with the following code
every f xs = liftM (all id) $ sequence $ map f xs
My function didn't work since it wasn't lazy (which was required in the question), so no upvotes there :-).
However, I did not stop there. I tried to make the function point-free so that it would be shorter (and perhaps even cooler). Since the arguments
f
andxs
are the last ones in the expression I just dropped them:every = liftM (all id) $ sequence $ map
But this did not work as expected, in fact it didn't work at all:
[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.Why is that? I was under the impression that it was possible to simply drop trailing function arguments, which basically is what currying is about.
解决方案The definition of $ is
f $ x = f x
Let's fully parenthesize your function:
every f xs = (liftM (all id)) (sequence ((map f) xs))
and your curried version:
every = (liftM (all id)) (sequence map)
As you noticed, these are not identical. You can only drop trailing function arguments when they are the last thing applied. For example,
f x = g c x
is actually
f x = (g c) x
and the application of (g c) to x comes last, so you can write
f = g c
One pattern with the application operator $ is that it often becomes the composition operator . in points-free versions. This is because
f $ g $ x
is equivalent to
(f . g) $ x
For example,
every f xs = liftM (all id) $ sequence $ map f xs
can become
every f xs = (liftM (all id) . sequence . map f) xs
at which point you can drop xs:
every f = liftM (all id) . sequence . map f
Eliminating the argument f is more difficult, because it is applied before the composition operator. Let's use the definition of dot from http://www.haskell.org/haskellwiki/Pointfree:
dot = ((.) . (.))
With points, this is
(f `dot` g) x = f . g x
and is exactly what we need to make every fully points-free:
every = (liftM (all id) . sequence) `dot` map
Sadly, due to restrictions in the Haskell type system, this one needs an explicit type signature:
every :: (Monad m) => (a -> m Bool) -> [a] -> m Bool
这篇关于在Haskell中关于currying和点自由风格的混淆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!