являются лево-ассоциативными, а операция возведения в степень ( ^) является право-ассоциативной.
1 +2 +3 ==(1 +2) +3
1 ^2 ^3 ==
1 ^(2 ^3)
Приоритет функции можно узнать в интерпретаторе с помощью команды :i:
*FunNat> :m Prelude
Prelude> :i ( +)
class( Eqa, Showa) => Numa where
( +) ::a ->a ->a
...
-- Defined in GHC.Num
infixl6 +
Prelude> :i ( *)
class( Eqa, Showa) => Numa where
...
( *) ::a ->a ->a
...
-- Defined in GHC.Num
infixl7 *
Prelude> :i ( ^)
( ^) ::( Numa, Integralb) =>a ->b ->a
-- Defined in GHC.Real
infixr8 ^
76 | Глава 5: Функции высшего порядка
Приоритет указывается в строчках infixl6 +и infixl7 *. Цифра указывает на старшинство операции,
а суффикс l (от англ. left – левая) или r (от англ. right – правая) на ассоциативность.
Если мы создали свою функцию, мы можем определить для неё ассоциативность. Для этого мы пишем в
коде:
module Fixity where
import Prelude( Num( ..))
infixl4 ***
infixl5 +++
infixr5 ‘neg‘
( ***) =( *)
( +++) =( +)
neg
=( -)
Мы ввели новые операции и поменяли старшинство операций сложения и умножения местами и изме-
нили ассоциативность у вычитания. Проверим в интерпретаторе:
Prelude> :l Fixity
[1 of1] Compiling Fixity
( Fixity.hs, interpreted )
Ok, modules loaded : Fixity.
*Fixity>1 +2 *3
7
*Fixity>1 +++2 ***3
9
*Fixity>1 -2 -3
-4
*Fixity>1 ‘neg‘ 2 ‘neg‘ 3
2
Посмотрим как это вычислялось:
1
+
2
*
3
==
1
+
(2
*
3)
1
+++
2
***3
==
(1
+++
2)
***
3
1
-
2
-
3
==
(1
-
2)
-
3
1 ‘neg‘ 2 ‘neg 3‘ ==
1 ‘neg‘ (2
‘neg‘ 3)
Также в Haskell есть директива infixэто тоже самое, что и infixl.
Приоритет функции композиции
Посмотрим на приоритет функции композиции:
Prelude> :i ( .)
( .) ::(b ->c) ->(a ->b) ->a ->c
-- Defined in GHC.Base
infixr9 .
Она имеет высший приоритет. Она очень часто используется при определении функции в бесточечном
стиле. Такая функция похожа на конвейер функций:
fun a =fun1 a .fun2 (x1 +x2) .fun3 .( +x1)
Приоритет функции применения
Теперь посмотрим на полное определение функции применения:
infixr0 $
( $) ::(a ->b) ->a ->b
f $x
=
f x
Ответ на вопрос о полезности этой функции кроется в её приоритете. Ей назначен самый низкий прио-
ритет. Она будет исполняться в последнюю очередь. Очень часто возникают ситуации вроде:
Приоритет инфиксных операций | 77
foldNat zero succ ( Succb) =succ (foldNat zero succ b)
С помощью функции применения мы можем переписать это определение так:
foldNat zero succ ( Succb) =succ $foldNat zero succ b
Если бы мы написали без скобок:
... =succ foldNat zero succ b
То выражение было бы сгруппировано так:
... =(((succ foldNat) zero) succ) b
Но поскольку мы поставили барьер в виде операции ( $) с низким приоритетом, группировка скобок
произойдёт так:
... =(succ $((foldNat zero) succ) b)
Это как раз то, что нам нужно. Преимущество этого подхода проявляется особенно ярко если у нас
несколько вложенных функций на конце выражения:
xs ::[ Int]
xs =reverse $map (( +1) .( *10)) $filter even $ns 40
ns :: Int ->[ Int]
ns 0
= []
ns n
=n :ns (n -1)
В списке xs мы сначала создаём в функции ns убывающий список чисел, затем оставляем лишь чётные,
Читать дальше