Если вы создадите функцию сравнения, которая отслеживает свои аргументы, например, в командной строке GHCi:
> :module + Data.List Debug.Trace
> let myCompare x y = trace ("\tCmp " ++ show x ++ " " ++ show y) $ compare x y
то вы можете сами увидеть поведение:
> sortBy myCompare "foobar"
" Cmp 'f' 'o'
Cmp 'o' 'b'
Cmp 'f' 'b'
Cmp 'a' 'r'
Cmp 'b' 'a'
a Cmp 'b' 'r'
b Cmp 'f' 'o'
Cmp 'f' 'r'
f Cmp 'o' 'o'
Cmp 'o' 'r'
o Cmp 'o' 'r'
or"
Haskell лениво оценивает строку, по одному символу за раз. Левая колонка печатается по мере нахождения каждого символа, а правая колонка записывает необходимые сравнения, напечатанные с помощью «трассировки».
Обратите внимание, что если вы скомпилируете это, особенно с включенной оптимизацией, вы можете получить другой результат. Оптимизатор запускает анализатор строгости, который, вероятно, заметит, что печатается вся строка, поэтому было бы более эффективно оценивать ее с нетерпением.
Тогда попробуй
> head $ sortBy myCompare "foobar"
Cmp 'f' 'o'
Cmp 'o' 'b'
Cmp 'f' 'b'
Cmp 'a' 'r'
Cmp 'b' 'a'
'a'
Если вы хотите понять, как это работает, найдите исходный код функции сортировки и оцените 'sort "foobar"' вручную на бумаге.
qsort [] = []
qsort (x:xs) = qsort less ++ [x] ++ qsort greater
where (less, greater) = partition (< x) xs
So
qsort ('f':"oobar")
= qsort ('b':"a") ++ "f" ++ qsort ('o':"or")
= ("a" ++ "b") ++ "f" ++ qsort ('o':"or")
И теперь мы сделали достаточно, чтобы обнаружить, что 'a' является первым элементом в результате, без необходимости оценивать другой вызов qsort. Я опустил фактическое сравнение, потому что оно скрыто внутри вызова «partition». На самом деле «раздел» также ленив, поэтому на самом деле аргумент другого «qsort» не оценивался, насколько я это показал.
person
Paul Johnson
schedule
01.12.2009