Давайте посмотрим, по кирпичику, может ли решение на основе foldr
замкнуть накоротко. Для начала, (&&)
определяется как это :
(&&) :: Bool -> Bool -> Bool
True && x = x
False && _ = False
Учитывая второе предложение и, благодаря лени, второй аргумент (&&)
игнорируется, если первый аргумент False
- другими словами, он закорачивает.
Далее это foldr
для списков :
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr k z = go
where
go [] = z
go (y:ys) = y `k` go ys
Если y `k` go ys
можно оценить, не глядя на go ys
, рекурсивного вызова не будет, и сгиб в целом будет сокращен.
В all1
бинарная операция \x acc -> acc && p x
. Это недостаточно для наших целей, поскольку передача acc
(что соответствует go ys
в определении foldr
) в качестве первого короткого замыкания аргумента (&&)
приводит к тому, что весь список используется независимо от того, из того, что p x
оказывается. Однако не все потеряно: обмен аргументов на (&&)
...
all3 :: (a -> Bool) -> [a] -> Bool
all3 p xs = foldr (\x acc -> p x && acc) True xs
... дает нам желаемое короткое замыкание.