我试图围绕着如何获得无限名单来解决这个问题......这是我的路障:
您有一个A
类型的列表,而A
实现了Ord
类型类。您可以像这样描述一系列有序元素(例如,intergers):
[1..6]
等同于......
Cons 1 (Cons 2 (Cons 3 (Cons 4 (Cons 5 (Cons 6 (Empty))))))
haskell如何知道如何构建无限列表? haskell能否创建支持Ord
的任何数据类型的无限列表?
答案 0 :(得分:6)
Haskell“创建”无限列表,因为它不需要创建任何元素。例如,让我们来看看head [1..]
的扩展,它在Haskell中产生1
,在严格语言中产生无限循环。
head [1..]
=== [expand `head`, literally
just inline the definition]
case [1..] of
[] -> error "empty list"
(x : xs) -> x
=== [evaluate [1..] one step,
check if it matches the case]
case 1:[2..] of
[] -> error "empty list"
(x : xs) -> x
=== [it does!]
(1 : [2..]) -> 1
=== [fin]
1
请注意,与大多数语言相比,这是非常落后的,这些语言首先攻击[1..]
的定义,而不是攻击head
。
你可以写[x..]
不是Ord
类型类中的任何类型(只能告诉我们两个事物是大于还是小于一个)而是Enum
中的任何类型} typeclass as [x..]
转换为enumFrom x
enumFrom :: Enum a => a -> [a]
。
答案 1 :(得分:4)
离开语法含糖[a..b]
的东西可能会容易一些,并想一想前奏中的一个简单函数:
repeat :: a -> [a]
repeat x = x : repeat x
你现在应该忘记评估并开始以声明的方式思考,即将上述内容想象成数学函数,可以阅读:
“重复x”表示“x”与“重复x”相对应
是的,“懒惰评估”是我们所说的能够让我们表达这一点的内容,但理想情况下,我们真的只想忘记评估并思考我们的代码意味着什么。在命令式编程中,您有义务始终考虑评估。
这或多或少是您的[1..]
desugars:
enumFrom n = n : enumFrom (succ n)
你可以在@ tel的回答中看到编译器如何扩展它。
答案 2 :(得分:0)
对于来自面向对象背景的人来说,无限列表的概念应该易于理解。
诀窍是将Haskell列表视为数组甚至是链表,而不是迭代器对象。迭代器对象是一个具有两个方法的对象hasNext
和getNext
。
通常,在有限数量的hasNext
调用之后,迭代器的False
将返回getNext
。如果你认为迭代器绑定到“真实”集合(如数组,哈希映射,文件等),那肯定是正确的。
但是没有任何东西固有地迫使迭代器变得“有限”。您可以非常轻松地实现无限迭代器。在类似Haskell的伪代码中:
object Iterator where
hasNext _ = True
getNext = do
state <- get
put (state + 1)
return state
如果你不知道这个迭代器是如何实现的,只要通过观察它的行为,你就会认为它与无限(或至少非常巨大)的集合有关。但它只是 - 一个返回连续数字的对象。
另一个类似的类比是UNIX中的特殊文件,例如/dev/zero
或/dev/random
。如果它们与硬盘上的真实文件绑定,则磁盘必须是无限的。但它们不是 - 相反,内容是由内核按需生成的,您可以根据需要尽可能多地使用它。
Haskell的惰性列表与此完全相同,除了它们还“缓冲”所有生成的值,以便您可以重复检查它们而无需重复评估。