【发布时间】:2021-11-06 20:03:47
【问题描述】:
foo s1 s2 = null ([x | x <- s2, x == s1])
请说明此功能何时结束?
Haskell 会先遍历整个列表然后检查null,还是当一个元素出现时,他会检查null 并完成迭代?如果是第一个选项,那怎么能更懒呢?
【问题讨论】:
标签: haskell list-comprehension
foo s1 s2 = null ([x | x <- s2, x == s1])
请说明此功能何时结束?
Haskell 会先遍历整个列表然后检查null,还是当一个元素出现时,他会检查null 并完成迭代?如果是第一个选项,那怎么能更懒呢?
【问题讨论】:
标签: haskell list-comprehension
Haskell 会先遍历整个列表,然后检查
null。
否。 null 检查它是否为空列表,并为空列表 [] 返回 True,为 (:) 数据构造函数返回 False。 “老”null is implemented as [src]:
null :: [a] -> Bool null [] = True null (_:_) = False
因此它将评估列表理解为head normal form(HNF),一旦它知道外部数据构造函数,它就可以返回True或False:它不会检查什么是第一个元素是,所以如果这是一个昂贵的表达式,它也不会在那个上浪费时间。
“新”null is implemented as [src]:
null :: t a -> Bool null = foldr (\_ _ -> False) True
foldr for a list is implemented as [src]:
foldr k z = go where go [] = z go (y:ys) = y `k` go ys
因此它还将简单地检查外部数据构造函数是空列表[] 还是“缺点”(:),因为在这种情况下k 返回True 并且对参数不感兴趣。
列表推导也是惰性的:它们只会在必要时评估外部数据构造函数,并在必要时构造头部和尾部。你的列表理解是:
concatMap (\x -> if x == s1 then [x] else []) s2
如果它因此必须评估列表的外部数据构造函数,它将遍历s2,如果x == s1 然后它将生成作为外部数据构造函数的“cons”,然后null 可以使用它判断列表是否为空。
因此,这意味着从它从 s2 找到元素 x 的那一刻起,它就会返回 False。
【讨论】: