2012-09-27 56 views

回答

18

断裂问题稍微开明分解成概念上的步骤:

  • 你想做些什么,以列表的每一个元素,这是由map函数提供的一般操作。使用它,你可以忽略这个列表,并且只考虑你需要用一个元素做什么。

  • 你想把两个数字相乘。在函数的任何一次使用中,这些数字中的一个将是常量,所以我们可以给它一个名称作为函数的参数:mult x = ...。现在我们可以把x作为一个常数,只考虑另一个数字。

  • 另一个数字不是常量,所以你需要一个函数,而不仅仅是一个简单的表达式。 Haskell提供“运营商部分”来完成这项工作,如(*)这样的中缀运营商,所以使用x我们得到了(x *)

  • 备份出来的最后几步,你现在给x的名称,并创建一个函数,你传递给map

mult x = map (x *) 

...和你实际上是在这一点上完成的,如果你想成为的话。但是,初学者可能会更清楚地列出一个明确的论点:

mult x ys = map (x *) ys 

虽然这两种形式都做同样的事情。

9

我最初有点不屑一顾golfy风格回答了这个,所以让我们再试一次。我的目的是双重的:赎回自己写的不知天高地厚的睡眠剥夺回答一个新人,:-),并尝试在该点自由风格提示:

mult_l = map . (*) 

是什么代码呢?

这是有帮助的流水线方式才想起来:

  • 该代码需要(*)饲料它map

  • (*)是什么类型的?那么,这是Num a => a -> a -> a。这意味着它确实什么?输入一个数字(称为x),并给你另一个函数,这个函数会 - 如果给出另一个数字(称之为y) - 计算x“times”y。 (我把“时代”括号因为Num是一个类型类...)

  • 现在你要组成(*)mapmap做什么?那么,让我们看看它的类型:(a -> b) -> [a] -> [b]。所以现在,map将函数作为参数并将该函数应用于列表的每个成员。

现在想想作文是如何工作的:(f . g) x = f (g x)

如果给一个说法,说2:

mult_l 2 

真的

(map . (*)) 2 

这是真的刚:现在

map (* 2) 

map有两个参数,它需要一个功能(它说“你想要我什么要做什么?“),它需要一个列表(它说”你想让我做什么?“)。 map然后获取该列表中的每个项目,并将该函数应用于元素。

这意味着,如果你把一样的东西:

map (* 2) [1,2,3] 

然后映射将采取列表,并期待在第一个元素,然后乘以2,再看第二个元素,等...

所以类型的map . (*)Num a => a -> [a] -> [a],因为它发生在一些x,然后到map喂高阶函数\x -> (* x)

现在你面临的挑战问题(因为你是哈斯克尔的新手),如何编写map?我会给你一个提示:

  • 如果你想在空列表上映射一个函数,那么你返回空列表。
  • 如果您想将功能映射到列表头部以及其尾部,请先将头部应用到头部,然后对列表的其余部分执行相同的操作。

在此之外,您将获得map的递归定义以及相关的归纳原理。

你可能会困惑的另一件事是:为什么我必须写map . (*)而不仅仅是map (*)。如果你仔细想想这一段时间,你可能会变得像到point free style

+2

确实,这些职业高尔夫球手会写'地图。(*)'并完成它。要达到这一点需要一些复杂性,所以感谢C.A.McCann记录大部分旅程。 – pigworker

+2

解释高尔夫FTW! – pigworker

6

由于没有人谈论列表解析,所以只是告诉另一种方式。

mult x ys = [i*x | i <- ys] 
+0

纯粹是为了我的兴趣,为什么downvote ..?我同意它不以同样的方式解释事情,并且可能不适合初学者,但@Satvik并没有声称它是,这是一个很好的选择 –

+0

@KristopherMicinski我更喜欢map自己的列表解析。我只是建议还有其他的方式来做这件事,你可以选择任何你喜欢的东西。 – Satvik

+0

我的理解是,我的问题依然存在,虽然对我来说也不是“规范”的方式,但我认为这不是一种倒退,它不是一种固有的坏方法,而且证明另一个目的是有启发性的。 –

相关问题