我觉得我对函数式编程的知识有些缺乏,所以我决定上网浏览并遵循教程,以使我在this的第一页上看到它时变得更好
“说您有一个不变的数字列表xs = [1,2,3,4,5,6,7,8]并且 一个doubleMe函数,它将每个元素乘以2,然后 返回一个新列表。如果我们想将列表中的数字乘以8 命令式语言,并做了doubleMe(doubleMe(doubleMe(xs))), 可能一次通过列表并进行复制然后返回 它。然后它将再次通过列表两次并返回 结果。”
根据我对函数式编程的了解,这似乎是错误的,让我向您展示原因:
doubleMe = (\x.* 2 x)
如此
doubleMe doubleMe doubleMe xs
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)
这意味着该函数的beta与(\ x。* 8 x)等效
给我的印象是,Haskell编译器在执行之前进行了这种简化,这意味着不,它不会像本教程所建议的那样遍历整个列表3次,只会进行一次。我错了吗?如果是这样,那么Haskell为什么不这样做?当然,它将大大改善性能。
答案 0 :(得分:4)
我认为您只是误读了该段。它说(强调我的):
如果我们想用命令式语言将列表乘以8 ,然后执行
>for (int i = 0; i < books.length; i++) { System.out.print("Enter book " + (i + 1) + " title: "); String title = input.nextLine(); // NOT HERE. input.nextLine(); System.out.println("Enter book " + (i + 1) + " author's name:"); String name = input.nextLine(); System.out.print("Enter book " + (i + 1) + " price: "); String pr = input.nextLine(); double price = Double.parseDouble(pr); System.out.println("Enter book " + (i + 1) + " author's email: "); String email = input.nextLine(); Author a = new Author(name, email); books[i] = new Book(title, price, a); System.out.println(books[i] + "\n"); }
,则它可能会通过列表一次,然后复制并返回。
命令式语言是C或Python之类的语言。不是Haskell。
同一段继续将这种行为与“惰性语言”的行为进行对比:
在一种懒惰的语言中……它只会在您真正需要时通过列表。这样,当您想要从懒惰的语言中获取某些东西时,您只需获取一些初始数据并有效地进行转换和修补,使其类似于最终所需的内容。
哪个更接近您的期望。