Apr 15, 2014 09:23
Хорошая хотя и простая задачка возникла в процессе проверки домашних заданий. Чем отличается поведение следующих двух функций, и в чем причина такого отличия:
diff xs = do
p <- zip xs (tail xs)
return $ abs (fst p - snd p)
diff' xs = do
p <- zip (tail xs) xs
return $ abs (fst p - snd p)
fprog,
haskell,
сборник задач и упражнений по Хаскелю,
fp
Leave a comment
Comments 13
Reply
Разница в том, что diff' [] вычисляет сначала tail [] и отваливается с ошибкой.
Т.е. у zip только второй аргумент лениво вычисляется.
Reply
> (\xs -> zip xs (tail $ tail xs)) [42]
*** Exception: Prelude.tail: empty list
Дело в том, что сопоставление с образцом всегда делается сверху вниз (по уравнениям) и слева направо (по образцам-параметрам текущего уравнения). Поэтому, если первый в текущем уравнении образец представлен конструктором, то для сопоставления соответствующий параметр передаваемый в функцию должен быть приведен в WHNF. А у zip оказывается так, что если WHNF - это пустой список, то выбирается второе уравнение, которому пофиг на второй аргумент.
Reply
Т.е. (если я правильно пользуюсь терминами) zip всегда строгий по первому агрументу, и иногда не строгий по второму. А сопоставление с образцом -- это причина строгости/нестрогости.
Reply
zip (a:as) (b:bs) = (a,b) : zip as bs
zip _ _ = []
Соответственно, zip [] (tail []) выдаёт пустой список, а zip (tail []) [] исключение.
Reply
zipWith (curry swap) ≡ flip zip
хотя казалось бы...
Reply
Reply
tail : (l : List a) -> (isCons l = True) -> List a
tail (x::xs) p = xs
zip : (l : List a) -> (r : List b) -> (length l = length r) -> List (a, b)
zip = zipWith (\x => \y => (x, y))
(List.idr) ;)
Reply
Reply
(The comment has been removed)
Reply
Leave a comment