Изучай Haskell во имя добра! (Липовача) - страница 62

. После вызова >scanl1 посмотрим, сколько элементов не превышают 1000. Первый элемент в результате работы функции >scanl1 должен быть равен единице. Второй будет равен 1 плюс квадратный корень двух. Третий элемент – это корень трёх плюс второй элемент. Если у нас x сумм меньших 1000, то нам потребовалось (x+1) элементов, чтобы превзойти 1000.

>sqrtSums :: Int

>sqrtSums = length (takeWhile (< 1000) (scanl1 (+) (map sqrt [1..]))) + 1


>ghci> sqrtSums

>131

>ghci> sum (map sqrt [1..131])

>1005.0942035344083

>ghci> sum (map sqrt [1..130])

>993.6486803921487

Мы задействовали функцию >takeWhile вместо >filter, потому что последняя не работает на бесконечных списках. В отличие от нас, функция >filter не знает, что список возрастает, поэтому мы используем >takeWhile, чтобы отсечь список, как только сумма превысит 1000.

Применение функций с помощью оператора $


Пойдём дальше. Теперь объектом нашего внимания станет оператор >$, также называемый аппликатором функций. Прежде всего посмотрим, как он определяется:

>($) :: (a –> b) –> a –> b

>f $ x = f x

Зачем? Что это за бессмысленный оператор? Это просто применение функции! Верно, почти, но не совсем!.. В то время как обычное применение функции (с пробелом) имеет высший приоритет, оператор >$ имеет самый низкий приоритет. Применение функции с пробелом левоассоциативно (то есть >f a b c i – это то же самое, что >(((f a) b) c)), в то время как применение функции при помощи оператора >$ правоассоциативно.

Всё это прекрасно, но нам-то с того какая польза? Прежде всего оператор >$ удобен тем, что с ним не приходится записывать много вложенных скобок. Рассмотрим выражение >sum (map sqrt [1..130]). Поскольку оператор >$ имеет самый низкий приоритет, мы можем переписать это выражение как >sum $ map sqrt [1..130], сэкономив драгоценные нажатия на клавиши. Когда в функции встречается знак >$, выражение справа от него используется как параметр для функции слева от него. Как насчёт >sqrt 3 + 4 + 9? Здесь складываются >9, >4 и корень из >3. Если мы хотим получить квадратный корень суммы, нам надо написать >sqrt (3 + 4 + 9) – или же (в случае использования оператора >$) >sqrt $ 3 + 4 + 9, потому что у оператора >$ низший приоритет среди всех операторов. Вот почему вы можете представить символ >$ как эквивалент записи открывающей скобки с добавлением закрывающей скобки в крайней правой позиции выражения.

Посмотрим ещё на один пример:

>ghci> sum (filter (> 10) (map (*2) [2..10]))

>80

Очень много скобок, даже как-то уродливо. Поскольку оператор $ правоассоциативен, выражение >f (g (z x)) эквивалентно записи