Haskell:带有元组的映射函数
我必须编写一个 Haskell 程序来执行以下操作:
Main> dotProduct [(1,3),(2,5),(3,3)] 2
[(2,3),(4,5),(6,3)]
我必须在使用和不使用 map
函数的情况下执行此操作。 我已经在没有 map
的情况下做到了这一点,但我不知道如何使用 map
做到这一点。
我的 dotProduct
没有 map
功能:
dotProduct :: [(Float, Integer)] -> Float -> [(Float, Integer)]
dotProduct [] _ = []
dotProduct [(x,y)] z = [(x*z,y)]
dotProduct ((x,y):xys) z = (x*z,y):dotProduct (xys) z
所以我真的需要 map
版本的帮助。
I have to write a Haskell program that does the following:
Main> dotProduct [(1,3),(2,5),(3,3)] 2
[(2,3),(4,5),(6,3)]
I have to do it both with and without map
function.
I already did it without map
, but I have no clue to do it with map
.
My dotProduct
without map
function:
dotProduct :: [(Float, Integer)] -> Float -> [(Float, Integer)]
dotProduct [] _ = []
dotProduct [(x,y)] z = [(x*z,y)]
dotProduct ((x,y):xys) z = (x*z,y):dotProduct (xys) z
So I really need help with the map
version.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不要从尝试以某种方式适应
map
开始,而是考虑如何简化和概括当前的函数。从这里开始:首先,我们将使用
(:)
构造函数重写第二种情况:使用第一种情况扩展结果中的
[]
:将其与第三种情况,我们可以看到它们是相同的,除了它专门用于当
xys
为[]
时。因此,我们可以简单地完全消除第二种情况:接下来,泛化该函数。首先,我们重命名它,并让
dotProduct
调用它:首先,我们通过操作对其进行参数化,专门用于
dotProduct
的乘法:接下来,我们可以观察到两件事:< code>generalized 不再直接依赖于算术,因此它可以适用于任何类型;唯一一次使用
z
是作为f
的第二个参数,因此我们可以将它们组合成一个函数参数:现在,我们注意到
f< /code> 仅用于元组的第一个元素。这听起来很有用,所以我们将其提取为一个单独的函数:
现在我们再次观察到,在
generalized
中,f
仅与onFirst
一起使用>,所以我们再次将它们组合成一个函数参数:并且我们再次观察到
generalized
不再依赖于包含元组的列表,因此我们让它在任何类型上工作:现在,比较
generalized
的代码如下:它也变成发现还存在稍微更通用的
onFirst
版本,因此我们将用其标准库等效项替换该版本和generalized
:Rather than starting by trying to fit
map
in somehow, consider how you might simplify and generalize your current function. Starting from this:First, we'll rewrite the second case using the
(:)
constructor:Expanding the
[]
in the result using the first case:Comparing this to the third case, we can see that they're identical except for this being specialized for when
xys
is[]
. So, we can simply eliminate the second case entirely:Next, generalizing the function. First, we rename it, and let
dotProduct
call it:First, we parameterize it by the operation, specializing to multiplication for
dotProduct
:Next, we can observe two things:
generalized
doesn't depend on arithmetic directly anymore, so it can work on any type; and the only timez
is used is as the second argument tof
, so we can combine them into a single function argument:Now, we note that
f
is only used on the first element of a tuple. This sounds useful, so we'll extract that as a separate function:Now we again observe that, in
generalized
,f
is only used withonFirst
, so we again combine them into a single function argument:And once again, we observe that
generalized
no longer depends on the list containing tuples, so we let it work on any type:Now, compare the code for
generalized
to this:It also turns out that a slightly more general version of
onFirst
also exists, so we'll replace both that andgeneralized
with their standard library equivalents:(\(x,y) -> (x*z,y))
部分是一个函数,它接受一对并返回一个新对,该新对与旧对类似,只是它的第一个组件是乘以z
。map
函数接受一个函数并将其应用于列表中的每个元素。因此,如果我们将(\(x,y) -> (x*z,y))
函数传递给map
,它将将该函数应用于中的每个元素xs
。虽然你确定你的第一个是正确的吗?点积运算通常被定义为将两个向量相乘,将相应的分量相乘,然后将它们全部相加。像这样:
The
(\(x,y) -> (x*z,y))
part is a function which takes a pair and returns a new pair that's like the old one, except its first component is multiplied byz
. Themap
function takes a function and applies it to each element in a list. So if we pass the(\(x,y) -> (x*z,y))
function tomap
, it will apply that function to every element inxs
.Although are you sure your first one is correct? The dot product operation is usually defined so that it takes two vectors, multiplies corresponding component and then sums it all together. Like this:
EEVIAC 已经发布了答案,所以我将解释如何自己想出答案。您可能知道,
map
具有类型签名(a -> b) ->; [一]-> [b]
。现在,dotProduct
的类型为[(Float, Integer)] ->浮动-> [(Float, Integer)]
并且您将在其中的某处调用map
,因此它必须看起来像这样:其中
???
是Float 类型的函数 -> (浮点数、整数)-> (Float, Integer)
- 这直接来自于map
的类型签名以及我们将z
传递给函数的事实,我们必须这样做,只是因为没有其他地方可以使用它。map
和高阶函数的一般情况是,您必须记住高阶函数的作用并“简单地”为其提供正确的功能。由于map
将给定函数应用于列表中的所有元素,因此您的函数只需要处理一个元素,并且您可以忘记列表的所有内容 -map
会照顾到它的。EEVIAC already posted the answer, so I'll just explain how to come up with it yourself. As you probably know,
map
has the type signature(a -> b) -> [a] -> [b]
. Now,dotProduct
has the type[(Float, Integer)] -> Float -> [(Float, Integer)]
and you'll callmap
somewhere in there, so it has to look something like this:where
???
is a function of typeFloat -> (Float, Integer) -> (Float, Integer)
- this follows immediately from the type signature ofmap
and from the fact that we passz
to the function, which we have to do, simply because there's no other place to use it in.The thing with
map
and higher order functions in general is that you have to keep in mind what the higher order function does and "simply" supply it with the correct function. Asmap
applies a given function to all elements in the list, your function only needs to work with one element, and you can forget all about the list -map
will take care of it.