无点Haskell中基于映射的乘法表
在Haskell中,我定义了一个乘法表生成器函数,如下所示:无点Haskell中基于映射的乘法表,haskell,pointfree,Haskell,Pointfree,在Haskell中,我定义了一个乘法表生成器函数,如下所示: multTable :: [[Int]] multTable=map (\b -> map (b*) [1..12]) [1..12] 哪个输出 [[1,2,3,4,5,6,7,8,9,10,11,12], [2,4,6,8,10,12,14,16,18,20,22,24], ...[12,24,36,48,60,72,84,96,108,120,132,144]] …如果你眯起眼睛,这看起来像是1..12的乘法表。到现在为
multTable :: [[Int]]
multTable=map (\b -> map (b*) [1..12]) [1..12]
哪个输出
[[1,2,3,4,5,6,7,8,9,10,11,12],
[2,4,6,8,10,12,14,16,18,20,22,24],
...[12,24,36,48,60,72,84,96,108,120,132,144]]
…如果你眯起眼睛,这看起来像是1..12的乘法表。到现在为止,一直都还不错。。。现在我试着让它没有任何意义,认为它应该很容易与组成。因此,我采取了一些小的步骤,我相信我已经走到了一半,因为我可以做到这一点:
map ($ 4) $ map (*) [1..12]
…这给了我:
[4,8,12,16,20,24,28,32,36,40,44,48]
看看这个,第二个映射给出了[a->a],这里是一个函数列表,它将值1到12乘以某个数字。第一个映射评估这些函数中的每一个,为它们提供值4,然后生成[4,8..]行
我不一定期望无点版本更简短,更简洁,甚至更可读。作为一名Haskell的新手,我只是想了解它是如何实现的。有一个叫做hackage的工具,它对你有极大的帮助(另请参阅)。它将创建以下版本:
multTable = map (flip map [1..12] . (*)) [1..12]
我们怎么去那里?好吧,让我们稍微移动操作符,并尝试在函数上应用flip
,直到得到类似的结果:
multTable = map (\b -> map (b*) [1..12]) [1..12]
= map (\b -> map ((*) b) [1..12]) [1..12] -- change to prefix notation
= map (\b -> flip map [1..12] ((*) b) [1..12] -- flip map
= map (\b -> flip map [1..12] . (*) $ b) [1..12] -- associativity
= map (flip map [1..12] . (*)) [1..12] -- eta-reduction
注意,我们只需要关注\b->map(b*)[1..12]
尽管如此,无点版本感觉有点做作。毕竟,您需要一个表,要创建一个表:列表理解:
multTable = [[x * y | x <- [1..12]] | y <- [1..12]]
multTable=[[x*y | x在对Zeta回答的评论中,他建议重新实现您的代码:
do
x <- [1..12]
return $ do
y <- [1..12]
return (x * y)
现在我突然想到,m>=\x->return(fx)
与fmap fm
是一样的,所以上面的代码实际上只需要Functor而不需要Monad
。所以这让我想知道什么是“Functor的do
-符号”可能看起来像,以及它将如何去糖化。定义for=flip fmap
,我认为它可能看起来是如何去糖化的:
for [1..12] $ \x ->
for [1..12] $ \y ->
x*y
(希望您能看到与desugareddo
-符号的相似之处。)在任何情况下,如果将其无点化,都会得到非常漂亮的结果:
for [1..12] $ for [1..12] . (*)
刚接触哈斯克尔的人似乎爱上了无点模式。爱情是盲目的,你会从中解脱出来。顺便说一句,这里有一个不错的(不是无点)版本:[[x*y | x@BenjaminHodgson如果他对它感兴趣,为什么不让他来?看看你能把一些编程技术或概念发展到什么程度很有趣。不管它最终是否实用,这都不一定重要。泽塔的回答在逐步细化方面很有启发性,从我的原创开始,以无点形式结束。丹尼尔s的答案有一个吸引人的风格,我觉得非常直观。两个答案都很好。谢谢。do
符号变体没有列表理解好:do{x“函子理解”版本特别好:let for=flip-fmap-in for[1..12]$\x->for[1..12]$\y->x*y
。如果您将其指向自由,您将获得[1..12]的,[1..12]的$(*)
这在我看来很漂亮。@DanielWagner:你想添加这个作为答案吗?它看起来真的很漂亮。我不小心在fmap
中省略了“f”,它仍然适用于你提供的其余表达式。这个翻转映射的(或fmap
)作为for
对我来说非常有意义。这是一个非常有趣的见解。@devgeezer是的,对于列表,fmap=map
。很高兴你喜欢它。
for [1..12] $ for [1..12] . (*)