Операторы (определяемые как функции без буквенно-цифровых символов в имени, которые используются в стиле инфикса) имеют более низкий приоритет, чем другие функции в Haskell. Поэтому ваше выражение:
map chr . map (1+) . map ord ['a', 'b', 'c', 'd', 'e']
анализируется как:
(map chr) . (map (1+)) . (map ord ['a', 'b', 'c', 'd', 'e'])
И это не имеет никакого смысла - оператор .
объединяет 2 функции, а map ord ['a', 'b', 'c', 'd', 'e']
- это не функция, а список чисел.
Но есть еще лучшие альтернативы вашей правильной версии со всеми вложенными скобками. То, что вы хотите сделать, это начать со списка символов и последовательно map
3 функции над ним. Это, по определению композиции функций, аналогично применению к ней композиции 3 map
s, то есть:
(map chr . map (1+) . map ord) ['a', 'b', 'c', 'd', 'e']
, который, как указывает @chi ниже, часто пишется так, используя оператор приложения функции $
(который имеет более низкий приоритет, чем любой другой оператор), чтобы избежать необходимости в скобках:
map chr . map (1+) . map ord $ ['a', 'b', 'c', 'd', 'e']
И, поскольку map f . map g
всегда совпадает с map (f . g)
(это должно быть очевидно, когда вы перестанете думать о том, что означают эти выражения - это также основной закон, которому должна удовлетворять операция map
, чтобы сделать Тип списка в Functor
), это можно записать как:
map (chr . (1+) . ord) ['a', 'b', 'c', 'd', 'e']
На мой взгляд, это лучшая и наиболее читаемая версия.
Хотя еще лучше, как снова отмечает @chi, использовать chr . (1+) . ord
эквивалентно succ
, встроенной функции для получения «следующего» значения типа, который может быть перечислен. Так что вы можете просто написать map succ ['a', 'b', 'c', 'd', 'e']