简体   繁体   English

函数评估在Haskell中如何工作

[英]How does function evaluation work in Haskell

I felt my knowledge of functional programming was a bit lacking so I decided to look online and follow a tutorial to get better when I cam across this where it states on the first page 我觉得我的函数式编程的知识是欠缺所以有点我决定去看看网上,并按照教程,以获得更好,当我遇到凸轮这个地方的第一页上指出

"Say you have an immutable list of numbers xs = [1,2,3,4,5,6,7,8] and a function doubleMe which multiplies every element by 2 and then returns a new list. If we wanted to multiply our list by 8 in an imperative language and did doubleMe(doubleMe(doubleMe(xs))), it would probably pass through the list once and make a copy and then return it. Then it would pass through the list another two times and return the result." “假设您有一个不变的数字xs = [1,2,3,4,5,6,7,8]列表,以及一个doubleMe函数,该函数将每个元素乘以2,然后返回一个新列表。如果我们想乘以我们用命令式语言将列表乘以8,然后执行doubleMe(doubleMe(doubleMe(doubleMe(xs)))),它可能会通过列表一次,然后进行复制然后返回,然后再通过列表两次,然后返回结果。”

From my knowledge of functional programming this seems wrong, let me show you why: 根据我对函数式编程的了解,这似乎是错误的,让我向您展示原因:

doubleMe = (\x.* 2 x)

so 所以

doubleMe doubleMe doubleMe xs

would beta reduce to: Beta会减少为:

(\x.* 2 x) doubleMe doubleMe xs ->beta
(* 2 doubleMe) doubleMe xs 
(* 2 (\x.* 2 x)) doubleMe xs ->eta
(\x.* 2 * 2 x) doubleMe  xs ->beta
(* 2 * 2 doubleMe)  xs
(* 2 * 2 (\x.* 2 x)) xs ->eta
(\x.* 2 * 2 * 2 x) xs ->beta
(* 2 * 2 * 2 xs) ->beta
(* 4 * 2 xs) -> beta
(* 8 xs)

which means the function is beta equivalent to (\\x. * 8 x) 这意味着该函数的beta与(\\ x。* 8 x)等价

I was under the impression the Haskell compiler carried out this reduction prior to execution, meaning no, it wouldn't make 3 passes over the list like this tutorial suggested, it would only make one. 我给人的印象是,Haskell编译器在执行之前进行了这种简化,这意味着不,它不会像本教程所建议的那样在列表上进行3次传递,而只会进行一次。 Am I wrong? 我错了吗? If so then why doesn't Haskell do this? 如果是这样,那么Haskell为什么不这样做? Surely it would make large improvements to performance. 当然,它将大大改善性能。

I think you're just misreading that paragraph. 我认为您只是误读了该段。 It says (emphasis mine): 它说(强调我的):

If we wanted to multiply our list by 8 in an imperative language and did doubleMe(doubleMe(doubleMe(xs))) , it would probably pass through the list once and make a copy and then return it. 如果我们想使用命令式语言将列表乘以8并doubleMe(doubleMe(doubleMe(xs))) ,则它可能会通过列表一次,然后进行复制然后返回。

An imperative language is a language like C or Python. 命令式语言是诸如C或Python之类的语言。 Not Haskell. 不是Haskell。

That same paragraph goes on to contrast that behavior with what a "lazy language" does: 该段继续将这种行为与“惰性语言”的行为进行对比:

In a lazy language ... it only does one pass through the list and only when you really need it. 用一种懒惰的语言...它只会在您真正需要时通过列表。 That way when you want something from a lazy language you can just take some initial data and efficiently transform and mend it so it resembles what you want at the end. 这样,当您想从懒惰的语言中获取某些东西时,您只需获取一些初始数据并有效地进行转换和修补,使其类似于最终所需的内容。

Which is closer to what you expect. 哪个更接近您的期望。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM